source: lumina/lumina-fm/MainUI.cpp @ 0494142

releng/10.0.3releng/10.1releng/10.1.1
Last change on this file since 0494142 was 0494142, checked in by Ken Moore <ken@…>, 9 months ago

Add auto-detection of multimedia file extensions into lumina-fm, and also add a function into libLumina for converting a mime-type into a list of file extensions.

  • Property mode set to 100644
File size: 50.2 KB
Line 
1//===========================================
2//  Lumina-DE source code
3//  Copyright (c) 2014, Ken Moore
4//  Available under the 3-clause BSD license
5//  See the LICENSE file for full details
6//===========================================
7#include "MainUI.h"
8#include "ui_MainUI.h"
9
10MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI){
11  ui->setupUi(this);
12  //Be careful about the QSettings setup, it must match the lumina-desktop setup
13  QSettings::setPath(QSettings::NativeFormat, QSettings::UserScope, QDir::homePath()+"/.lumina");
14  settings = new QSettings( QSettings::UserScope, "LuminaDE", "lumina-fm", this);
15  //initialize the non-ui widgets
16  tabBar = new QTabBar(this);
17    tabBar->setTabsClosable(true);
18    tabBar->setMovable(true); //tabs are independant - so allow the user to sort them
19    tabBar->setShape(QTabBar::RoundedNorth);
20    tabBar->setFocusPolicy(Qt::NoFocus);
21    ui->verticalLayout_browser->insertWidget(0,tabBar);
22  currentDir = new QLineEdit(this);
23    ui->toolBar->insertWidget(ui->actionBookMark, currentDir);
24    currentDir->setFocusPolicy(Qt::StrongFocus);
25  fsmod = new QFileSystemModel(this);
26    fsmod->setRootPath("/");
27  dirCompleter = new QCompleter(fsmod, this);
28    dirCompleter->setModelSorting( QCompleter::CaseInsensitivelySortedModel );
29    currentDir->setCompleter(dirCompleter);
30  dirWatcher = new QFileSystemWatcher(this);
31    dirWatcher->addPath(QDir::homePath());
32   
33  snapmod = new QFileSystemModel(this);
34    ui->tree_zfs_dir->setModel(snapmod);
35    ui->tree_zfs_dir->sortByColumn(0, Qt::AscendingOrder);
36  contextMenu = new QMenu(this);
37  radio_view_details = new QRadioButton(tr("Detailed List"), this);
38  radio_view_list = new QRadioButton(tr("Basic List"), this);
39  radio_view_icons = new QRadioButton(tr("Icons"), this);
40  detWA = new QWidgetAction(this);
41    detWA->setDefaultWidget(radio_view_details);
42  listWA = new QWidgetAction(this);
43    listWA->setDefaultWidget(radio_view_list);
44  icoWA = new QWidgetAction(this);
45    icoWA->setDefaultWidget(radio_view_icons);
46    ui->menuView->addAction(detWA);
47    ui->menuView->addAction(listWA);
48    ui->menuView->addAction(icoWA);
49  //Setup the special Phonon widgets
50  mediaObj = new Phonon::MediaObject(this);
51    mediaObj->setTickInterval(200); //1/5 second ticks for updates
52  videoDisplay = new Phonon::VideoWidget(this);
53    videoDisplay->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
54    ui->videoLayout->addWidget(videoDisplay);
55    Phonon::createPath(mediaObj, videoDisplay);
56    videoDisplay->setVisible(false);
57  audioOut = new Phonon::AudioOutput(Phonon::VideoCategory, this);
58    Phonon::createPath(mediaObj, audioOut);
59  playerSlider = new Phonon::SeekSlider(this);
60    playerSlider->setMediaObject(mediaObj);
61    ui->videoControlLayout->insertWidget(4, playerSlider);
62  playerFile = new QFile();
63    ui->tool_player_stop->setEnabled(false); //nothing to stop yet
64    ui->tool_player_pause->setVisible(false); //nothing to pause yet
65   
66  //Setup any specialty keyboard shortcuts
67  nextTabLShort = new QShortcut( QKeySequence(tr("Shift+Left")), this);
68  nextTabRShort = new QShortcut( QKeySequence(tr("Shift+Right")), this);
69  closeTabShort = new QShortcut( QKeySequence(tr("Ctrl+W")), this);
70  copyFilesShort = new QShortcut( QKeySequence(tr("Ctrl+C")), this);
71  pasteFilesShort = new QShortcut( QKeySequence(tr("Ctrl+V")), this);
72  deleteFilesShort = new QShortcut( QKeySequence(tr("Delete")), this);
73  //Finish loading the interface
74  setupIcons();
75  setupConnections();
76  loadSettings();
77  RebuildBookmarksMenu();
78  RebuildDeviceMenu();
79  //Make sure we start on the browser page
80  goToBrowserPage();
81}
82
83MainUI::~MainUI(){
84       
85}
86
87void MainUI::OpenDirs(QStringList dirs){
88  for(int i=0; i<dirs.length(); i++){
89    //Add this directory in a new tab
90    if(dirs[i].endsWith("/")){ dirs[i].chop(1); }
91    qDebug() << "Open Directory:" << dirs[i];
92    int index = tabBar->addTab( dirs[i].section("/",-1) );
93    tabBar->setTabWhatsThis( index, dirs[i] );
94    if(index==0){ setCurrentDir(dirs[i]); }//display this as the current dir
95  }
96  tabBar->setVisible( tabBar->count() > 1 );
97}
98
99//==========
100//    PRIVATE
101//==========
102void MainUI::setupIcons(){
103  this->setWindowIcon( LXDG::findIcon("system-file-manager","") );
104       
105  //Setup all the icons using libLumina
106  ui->actionClose->setIcon( LXDG::findIcon("application-exit","") );
107  ui->actionNew_Tab->setIcon( LXDG::findIcon("tab-new-background","") );
108  //ui->action_Preferences->setIcon( LXDG::findIcon("configure","") );
109  ui->actionUpDir->setIcon( LXDG::findIcon("go-up","") );
110  ui->actionBack->setIcon( LXDG::findIcon("go-previous","") );
111  ui->actionHome->setIcon( LXDG::findIcon("go-home","") );
112  ui->actionBookMark->setIcon( LXDG::findIcon("bookmarks","") );
113  ui->actionBackToBrowser->setIcon( LXDG::findIcon("go-previous","") );
114  ui->actionManage_Bookmarks->setIcon( LXDG::findIcon("bookmarks-organize","") );
115  ui->actionScan->setIcon( LXDG::findIcon("system-search","") );
116       
117  //Browser page
118  ui->tool_addToDir->setIcon( LXDG::findIcon("folder-new","") );
119  ui->tool_goToImages->setIcon( LXDG::findIcon("fileview-preview","") );
120  ui->tool_goToPlayer->setIcon( LXDG::findIcon("applications-multimedia","") );
121  ui->tool_goToRestore->setIcon( LXDG::findIcon("document-revert","") );
122       
123  //Multimedia Player page
124  ui->tool_player_next->setIcon( LXDG::findIcon("media-skip-forward","") );
125  ui->tool_player_prev->setIcon( LXDG::findIcon("media-skip-backward","") );
126  ui->tool_player_pause->setIcon( LXDG::findIcon("media-playback-pause","") );
127  ui->tool_player_play->setIcon( LXDG::findIcon("media-playback-start","") );
128  ui->tool_player_stop->setIcon( LXDG::findIcon("media-playback-stop","") );
129       
130  //Slideshow page
131  ui->tool_image_goBegin->setIcon( LXDG::findIcon("go-first-view","") );
132  ui->tool_image_goEnd->setIcon( LXDG::findIcon("go-last-view","") );
133  ui->tool_image_goPrev->setIcon( LXDG::findIcon("go-previous-view","") );
134  ui->tool_image_goNext->setIcon( LXDG::findIcon("go-next-view","") );
135 
136  //ZFS Restore page
137  ui->tool_zfs_nextSnap->setIcon( LXDG::findIcon("go-next-view","") );
138  ui->tool_zfs_prevSnap->setIcon( LXDG::findIcon("go-previous-view","") );
139  ui->tool_zfs_restoreItem->setIcon( LXDG::findIcon("document-revert","") );
140}
141
142void MainUI::setupConnections(){
143  connect(QApplication::instance(), SIGNAL(focusChanged(QWidget*, QWidget*)), this, SLOT(startEditDir(QWidget*, QWidget*)) );
144  connect(tabBar, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)) );
145  connect(tabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(tabClosed(int)) );
146  connect(ui->menuBookmarks, SIGNAL(triggered(QAction*)), this, SLOT(goToBookmark(QAction*)) );
147  connect(ui->menuExternal_Devices, SIGNAL(triggered(QAction*)), this, SLOT(goToDevice(QAction*)) );
148  connect(currentDir, SIGNAL(returnPressed()), this, SLOT(goToDirectory()));
149  connect(radio_view_details, SIGNAL(toggled(bool)), this, SLOT(viewModeChanged(bool)) );
150  connect(radio_view_list, SIGNAL(toggled(bool)), this, SLOT(viewModeChanged(bool)) );
151  connect(radio_view_icons, SIGNAL(toggled(bool)), this, SLOT(viewModeChanged(bool)) );
152       
153  //Tree Widget interaction
154  connect(ui->tree_dir_widget, SIGNAL(itemActivated(QTreeWidgetItem*, int)), this, SLOT(ItemRun(QTreeWidgetItem*)) );
155  connect(ui->list_dir_widget, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(ItemRun(QListWidgetItem*)) );
156  connect(ui->tree_dir_widget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OpenContextMenu(const QPoint&)) );
157  connect(ui->list_dir_widget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OpenContextMenu(const QPoint&)) );
158  connect(dirWatcher, SIGNAL(directoryChanged(QString)), this, SLOT( loadDirectory() ) );
159       
160  //Page Switching
161  connect(ui->tool_goToPlayer, SIGNAL(clicked()), this, SLOT(goToMultimediaPage()) );
162  connect(ui->tool_goToRestore, SIGNAL(clicked()), this, SLOT(goToRestorePage()) );
163  connect(ui->tool_goToImages, SIGNAL(clicked()), this, SLOT(goToSlideshowPage()) );
164  connect(ui->actionBackToBrowser, SIGNAL(triggered()), this, SLOT(goToBrowserPage()) );
165       
166  //Slideshow page
167  connect(ui->combo_image_name, SIGNAL(currentIndexChanged(int)), this, SLOT(showNewPicture()) );
168  connect(ui->tool_image_goBegin, SIGNAL(clicked()), this, SLOT(firstPicture()) );
169  connect(ui->tool_image_goEnd, SIGNAL(clicked()), this, SLOT(lastPicture()) );
170  connect(ui->tool_image_goNext, SIGNAL(clicked()), this, SLOT(nextPicture()) );
171  connect(ui->tool_image_goPrev, SIGNAL(clicked()), this, SLOT(prevPicture()) );
172       
173  //ZFS Restore page
174  connect(snapmod, SIGNAL(directoryLoaded(QString)), this, SLOT(snapshotLoaded()) );
175  connect(ui->slider_zfs_snapshot, SIGNAL(valueChanged(int)), this, SLOT(showSnapshot()) );
176  connect(ui->tool_zfs_nextSnap, SIGNAL(clicked()), this, SLOT(nextSnapshot()) );
177  connect(ui->tool_zfs_prevSnap, SIGNAL(clicked()), this, SLOT(prevSnapshot()) );
178  connect(ui->tool_zfs_restoreItem, SIGNAL(clicked()), this, SLOT(restoreItems()) );
179 
180  //Multimedia Player page
181  connect(ui->tool_player_next, SIGNAL(clicked()), this, SLOT(playerNext()));
182  connect(ui->tool_player_prev, SIGNAL(clicked()), this, SLOT(playerPrevious()));
183  connect(ui->tool_player_pause, SIGNAL(clicked()), this, SLOT(playerPause()));
184  connect(ui->tool_player_play, SIGNAL(clicked()), this, SLOT(playerStart()));
185  connect(ui->tool_player_stop, SIGNAL(clicked()), this, SLOT(playerStop()));
186  connect(ui->combo_player_list, SIGNAL(currentIndexChanged(int)), this, SLOT(playerFileChanged()) );
187  connect(mediaObj, SIGNAL(finished()), this, SLOT(playerFinished()) );
188  connect(mediaObj, SIGNAL(tick(qint64)), this, SLOT(playerTimeChanged(qint64)) );
189  connect(mediaObj, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(playerStateChanged(Phonon::State, Phonon::State)) );
190  connect(mediaObj, SIGNAL(hasVideoChanged(bool)), this, SLOT(playerVideoAvailable(bool)) );
191  //Special Keyboard Shortcuts
192  connect(nextTabLShort, SIGNAL(activated()), this, SLOT( prevTab() ) );
193  connect(nextTabRShort, SIGNAL(activated()), this, SLOT( nextTab() ) );
194  connect(closeTabShort, SIGNAL(activated()), this, SLOT( tabClosed() ) );
195  connect(copyFilesShort, SIGNAL(activated()), this, SLOT( CopyItems() ) );
196  connect(pasteFilesShort, SIGNAL(activated()), this, SLOT( PasteItems() ) );
197  connect(deleteFilesShort, SIGNAL(activated()), this, SLOT( RemoveItem() ) );
198}
199
200void MainUI::loadSettings(){
201  //Note: make sure this is run after all the UI elements are created and connected to slots
202  // but before the first directory gets loaded
203  ui->actionView_Hidden_Files->setChecked( settings->value("showhidden", false).toBool() );
204  on_actionView_Hidden_Files_triggered(); //make sure to update the models too
205  QString view = settings->value("viewmode","details").toString();
206  if(view=="icons"){ radio_view_icons->setChecked(true); }
207  else if(view=="list"){ radio_view_list->setChecked(true); }
208  else{ radio_view_details->setChecked(true); }
209}
210
211void MainUI::RebuildBookmarksMenu(){
212  //Create the bookmarks menu
213  ui->menuBookmarks->clear();
214    ui->menuBookmarks->addAction(ui->actionManage_Bookmarks);
215    ui->menuBookmarks->addSeparator();
216  QStringList BM = settings->value("bookmarks", QStringList()).toStringList();
217  ui->menuBookmarks->clear();
218    ui->menuBookmarks->addAction(ui->actionManage_Bookmarks);
219    ui->menuBookmarks->addSeparator();
220  bool changed = false;
221  BM.sort(); //Sort alphabetically
222  for(int i=0; i<BM.length(); i++){
223    if(QFile::exists(BM[i].section("::::",1,1)) ){
224      QAction *act = new QAction(BM[i].section("::::",0,0),this);
225        act->setWhatsThis(BM[i].section("::::",1,1));
226      ui->menuBookmarks->addAction(act);
227    }else{
228      //Invalid directory - remove the bookmark
229      BM.removeAt(i);
230      i--;
231      changed = true;
232    }
233  }
234  if(changed){ settings->setValue("bookmarks",BM); }
235  ui->actionManage_Bookmarks->setEnabled(BM.length()>0);
236}
237
238void MainUI::RebuildDeviceMenu(){
239  //Create the External Devices Menu appropriately
240  ui->menuExternal_Devices->clear();
241    ui->menuExternal_Devices->addAction( ui->actionScan );
242    ui->menuExternal_Devices->addSeparator();
243  //Scan for externally mounted devices
244  QStringList devs = LOS::ExternalDevicePaths();
245    //Output Format: <type>::::<filesystem>::::<path>  (6/24/14 - version 0.4.0 )
246        // <type> = [USB, HDRIVE, SDCARD, DVD, UNKNOWN]
247       
248  //Now add them to the menu appropriately
249  for(int i=0; i<devs.length(); i++){
250    QAction *act = new QAction(devs[i].section("::::",2,2).section("/",-1),this);
251        act->setWhatsThis(devs[i].section("::::",2,2)); //full path to mountpoint
252        act->setToolTip( QString(tr("Filesystem: %1")).arg( devs[i].section("::::",1,1) ) );
253        //Now set the appropriate icon
254        QString type = devs[i].section("::::",0,0);
255        if(type=="USB"){ type = "drive-removable-media-usb"; }
256        else if(type=="HDRIVE"){ type = "drive-harddisk"; }
257        else if(type=="SDCARD"){ type = "media-flash-sd-mmc"; }
258        else if(type=="DVD"){ type = "media-optical"; }
259        else{ type = "drive-removable-media"; }
260        act->setIcon( LXDG::findIcon(type, "") );
261      ui->menuExternal_Devices->addAction(act);
262  }
263}
264
265bool MainUI::checkUserPerms(){
266  if(!isUserWritable){
267    QMessageBox::warning(this, tr("Invalid Permissions"), tr("You do not have permission to edit this directory!") );
268  }
269  return isUserWritable;
270}
271
272QString MainUI::bytesToText(qint64 bytes){
273  QString lab; //label
274  double disp; //display number
275  if(bytes > 1125899906842580){ lab="PB"; disp = bytes/1125899906842580.0; }
276  else if(bytes>1099511627776){ lab="TB"; disp = bytes/1099511627776.0; }
277  else if(bytes>1073741824){ lab="GB"; disp = bytes/1073741824.0; }
278  else if(bytes>1048576){ lab="MB"; disp = bytes/1048576.0; }
279  else if(bytes>1024){ lab="KB"; disp = bytes/1024.0; }
280  else{ lab="B"; disp = bytes; }
281  //Round to number of decimel places
282  if(disp<10){ disp = qRound(disp*100)/(100.0); } //2 decimel places
283  else if(disp<100){ disp = qRound(disp*10)/(10.0); } //1 decimel place
284  else{ disp = qRound(disp); } // no decimel places
285  //Return text
286  return QString::number(disp)+" "+lab;
287}
288
289QString MainUI::msToText(qint64 ms){
290  QString disp;
291  if(ms>3600000){
292    disp.append( QString::number(ms/3600000)+":" ); 
293    ms = ms%3600000; 
294  }
295  if(ms>60000){
296    disp.append( QString::number(ms/60000)+":" );
297    ms = ms%60000;
298  }else{
299    disp.append("0:");
300  }
301  if(ms>1000){
302    if(ms>=10000){ disp.append( QString::number(ms/1000) ); }
303    else{ disp.append( "0"+QString::number(ms/1000) ); }
304  }else{
305    disp.append("00");
306  }
307  return disp;
308}
309
310QString MainUI::getCurrentDir(){
311  return currentDir->whatsThis();
312}
313
314void MainUI::setCurrentDir(QString dir){
315  if(dir.isEmpty()){ return; }
316  QFileInfo info(dir);
317  if(!info.isDir() || !info.exists() ){ 
318    qDebug() << "Invalid Directory:" << dir;
319    //Try to just go up the dir tree one level
320    dir.chop(dir.section("/",-1).length());
321    if(!QFile::exists(dir)){
322      //Still bad dir - try to return to previously shown dir
323      if(currentDir->whatsThis().isEmpty()){ return; } //nothing to return to
324      else{ dir = currentDir->whatsThis(); }
325    }
326  }
327  //qDebug() << "Show Directory:" << dir;
328  //qDebug() << "Dir Info:" << dir;
329  //qDebug() << " - RWXLOG:" << info.isReadable() << info.isWritable() << info.isExecutable() << info.isSymLink() << info.ownerId() << info.groupId();
330  isUserWritable = info.isWritable();
331  if(dir.endsWith("/") && dir!="/" ){ dir.chop(1); }
332  QString rawdir = dir;
333  //dir.replace(QDir::homePath()+"/", "~/");
334  currentDir->setText(dir); 
335  //Update the directory viewer and update the line edit
336  if(dir!=currentDir->whatsThis()){
337    keepFocus = !currentDir->hasFocus();
338    currentDir->setWhatsThis(dir); //save the full path internally
339    //fsmod->setRootPath(dir);
340    QTimer::singleShot(0,this, SLOT(loadDirectory()) );
341  }
342  dirWatcher->removePaths( dirWatcher->directories() );
343  dirWatcher->addPath(rawdir); //make sure we are watching this directory
344  //Adjust the tab data
345  tabBar->setTabWhatsThis( tabBar->currentIndex(), rawdir );
346  if(dir!="/"){ tabBar->setTabText( tabBar->currentIndex(), dir.section("/",-1) ); }
347  else{ tabBar->setTabText( tabBar->currentIndex(), dir); }
348  QStringList history = tabBar->tabData(tabBar->currentIndex()).toStringList();
349  if(history.isEmpty() || history.first()!=rawdir){ history.prepend(rawdir); history.removeAll(""); }
350  //qDebug() << "History:" << history;
351  tabBar->setTabData(tabBar->currentIndex(), history);
352  //Now adjust the items as necessary
353  QTimer::singleShot(0, this, SLOT(checkForMultimediaFiles()));
354  QTimer::singleShot(0, this, SLOT(checkForBackups()));
355  QTimer::singleShot(0, this, SLOT(checkForPictures()));
356  ui->tool_addToDir->setVisible(isUserWritable);
357  ui->actionUpDir->setEnabled(dir!="/");
358  ui->actionBack->setEnabled(history.length() > 1);
359  ui->actionBookMark->setEnabled( rawdir!=QDir::homePath() && settings->value("bookmarks", QStringList()).toStringList().filter("::::"+rawdir).length()<1 );
360  RebuildDeviceMenu(); //keep this refreshed
361}
362
363QStringList MainUI::getSelectedItems(){
364  QStringList out;
365  if(radio_view_details->isChecked()){
366    QList<QTreeWidgetItem*> items = ui->tree_dir_widget->selectedItems();
367    for(int i=0; i<items.length(); i++){
368       out << items[i]->text(0);
369    }
370  }else{
371    QList<QListWidgetItem*> items = ui->list_dir_widget->selectedItems();
372    for(int i=0; i<items.length(); i++){
373       out << items[i]->text();
374    }
375  }     
376  out.removeDuplicates();
377  return out;
378}
379
380//==============
381//    PRIVATE SLOTS
382//==============
383//General button check functions
384void MainUI::checkForMultimediaFiles(){
385  ui->tool_goToPlayer->setVisible(false);
386  //Check for multimedia files not implemented yet!
387  QDir dir(getCurrentDir());
388  if(multiFilter.isEmpty()){
389    QStringList mimes = Phonon::BackendCapabilities::availableMimeTypes();
390    mimes = mimes.filter("audio/") + mimes.filter("video/");
391    for(int i=0; i<mimes.length(); i++){
392      multiFilter << LXDG::findFilesForMime(mimes[i]);
393    }
394    multiFilter.removeDuplicates();
395    qDebug() << "Supported Multimedia Formats:" << multiFilter;
396  }
397  QStringList files = dir.entryList(multiFilter, QDir::Files | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase);
398  if(!files.isEmpty()){
399    ui->combo_player_list->clear();
400    ui->combo_player_list->addItems(files);
401    ui->tool_goToPlayer->setVisible(true);
402  }
403 
404}
405
406void MainUI::checkForBackups(){
407  ui->tool_goToRestore->setVisible(false);
408  //Check for ZFS snapshots not implemented yet!
409  snapDirs.clear(); //clear the internal variable
410  if(!isUserWritable){ return; } //cannot restore files into a non-writable directory
411  //Now recursively try to find snapshots of this directory
412  QString cdir = getCurrentDir();
413  QDir dir(cdir);
414  bool found = false;
415  while(dir.absolutePath()!="/" && !found){
416    if(dir.exists(".zfs/snapshot")){ found = true;}
417    else{ dir.cdUp(); }
418  }
419  //Now find the snapshots that contain this directory and save them
420  if(found){
421    QString reldir = getCurrentDir();
422          reldir.remove(dir.absolutePath());
423    dir.cd(".zfs/snapshot");
424    snapDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Time);
425    //Check that the current directory exists in each snapshot
426    for(int i=0; i<snapDirs.length(); i++){
427      if( !dir.exists(snapDirs[i]+"/"+reldir) ){
428        snapDirs.removeAt(i);
429        i--;
430      }else{
431        snapDirs[i] = QFileInfo(dir, snapDirs[i]+"/"+reldir).created().toString("yyyyMMddhhmmsszzz")+"::::"+snapDirs[i];
432      }
433    }
434    snapDirs.sort();
435    //Sort the snapshots by time (newest last) and format them
436    for(int i=0; i<snapDirs.length(); i++){
437      snapDirs[i] = dir.absolutePath()+"/"+snapDirs[i].section("::::",1,50)+"/"+reldir;
438    }
439    //qDebug() << "Found snapshots:" << snapDirs;
440  }
441  //Now enable the button if any snapshots available
442  ui->tool_goToRestore->setVisible(!snapDirs.isEmpty());
443}
444
445void MainUI::checkForPictures(){
446  ui->tool_goToImages->setVisible(false);
447  QDir dir(getCurrentDir());
448  if(imgFilter.isEmpty()){
449    QList<QByteArray> fmt = QImageReader::supportedImageFormats();
450    for(int i=0; i<fmt.length(); i++){ imgFilter << "*."+QString(fmt[i]).toLower(); }
451    qDebug() << "Supported Image Formats:" << imgFilter;
452  }
453  QStringList pics = dir.entryList(imgFilter, QDir::Files | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase);
454  if(!pics.isEmpty()){
455    ui->combo_image_name->clear();
456    for(int i=0; i<pics.length(); i++){
457      ui->combo_image_name->addItem(QIcon(dir.absoluteFilePath(pics[i])), pics[i]);
458    }
459    ui->tool_goToImages->setVisible(true);       
460  }
461       
462}
463
464//-----------------------------------
465//General page switching
466//-----------------------------------
467void MainUI::goToMultimediaPage(){
468  //Make toolbar items disappear appropriately 
469  ui->actionBackToBrowser->setVisible(true);
470  ui->actionBack->setVisible(false);
471  ui->actionUpDir->setVisible(false);
472  ui->actionHome->setVisible(false);
473  ui->actionBookMark->setVisible(false);
474  currentDir->setEnabled(false);
475  //Disable all the UI elements specifically for the Browser side of things
476  ui->actionNew_Tab->setEnabled(false);
477  //ui->menuEdit->setEnabled(false);
478  ui->menuView->setEnabled(false);
479  ui->menuBookmarks->setEnabled(false);
480  ui->menuExternal_Devices->setEnabled(false);
481  //Start the player on the first selected item
482  QStringList sel = getSelectedItems();
483  if(!sel.isEmpty()){
484    //start the slideshow on the first selected picture
485    for(int i=0; i<ui->combo_player_list->count(); i++){
486      if(sel.contains( ui->combo_player_list->itemText(i) )){ ui->combo_player_list->setCurrentIndex(i); break; }
487    }
488  }
489  //Now go to the Multimedia player
490  ui->label_player_novideo->setText(tr("Click Play to Start"));
491  ui->stackedWidget->setCurrentWidget(ui->page_audioPlayer);
492}
493
494void MainUI::goToRestorePage(){
495  //Make toolbar items disappear appropriately
496  ui->actionBackToBrowser->setVisible(true);   
497  ui->actionBack->setVisible(false);
498  ui->actionUpDir->setVisible(false);
499  ui->actionHome->setVisible(false);
500  ui->actionBookMark->setVisible(false);
501  currentDir->setEnabled(false);
502  //Disable all the UI elements specifically for the Browser side of things
503  ui->actionNew_Tab->setEnabled(false);
504  //ui->menuEdit->setEnabled(false);
505  ui->menuView->setEnabled(false);
506  ui->menuBookmarks->setEnabled(false);
507  ui->menuExternal_Devices->setEnabled(false);
508  //Load all the info into the file restore page
509  ui->slider_zfs_snapshot->setRange(1,snapDirs.length());
510  ui->slider_zfs_snapshot->setValue(snapDirs.length());
511  //Now go to the file restore page
512  showSnapshot(); //Make sure it is updated for the current directory
513  ui->stackedWidget->setCurrentWidget(ui->page_zfs);   
514}
515
516void MainUI::goToSlideshowPage(){
517  //Make toolbar items disappear appropriately 
518  ui->actionBackToBrowser->setVisible(true);
519  ui->actionBack->setVisible(false);
520  ui->actionUpDir->setVisible(false);
521  ui->actionHome->setVisible(false);
522  ui->actionBookMark->setVisible(false);
523  currentDir->setEnabled(false);
524  //Disable all the UI elements specifically for the Browser side of things
525  ui->actionNew_Tab->setEnabled(false);
526  //ui->menuEdit->setEnabled(false);
527  ui->menuView->setEnabled(false);
528  ui->menuBookmarks->setEnabled(false);
529  ui->menuExternal_Devices->setEnabled(false);
530  QStringList sel = getSelectedItems();
531  if(!sel.isEmpty()){
532    //start the slideshow on the first selected picture
533    for(int i=0; i<ui->combo_image_name->count(); i++){
534      if(sel.contains( ui->combo_image_name->itemText(i) )){ ui->combo_image_name->setCurrentIndex(i); break; }
535    }
536  }
537  //Now go to the Slideshow player
538  ui->stackedWidget->setCurrentWidget(ui->page_image_view);
539  showNewPicture(); //make sure it is up to date with the widget size
540}
541
542void MainUI::goToBrowserPage(){
543  //Make toolbar items re-appear appropriately 
544  ui->actionBackToBrowser->setVisible(false);
545  ui->actionBack->setVisible(true);
546  ui->actionUpDir->setVisible(true);
547  ui->actionHome->setVisible(true);
548  ui->actionBookMark->setVisible(true);
549  currentDir->setEnabled(true);
550  //Disable all the UI elements specifically for the Browser side of things
551  ui->actionNew_Tab->setEnabled(true);
552  //ui->menuEdit->setEnabled(true);
553  ui->menuView->setEnabled(true);
554  ui->menuBookmarks->setEnabled(true);
555  ui->menuExternal_Devices->setEnabled(true);
556  //Now go to the browser
557  if(ui->stackedWidget->currentWidget()==ui->page_audioPlayer){ mediaObj->stop(); }
558  ui->stackedWidget->setCurrentWidget(ui->page_browser);       
559}
560       
561//---------------------
562//Menu Actions
563//---------------------
564void MainUI::on_actionNew_Tab_triggered(){
565  OpenDirs(QStringList() << QDir::homePath());
566  //Now go to that tab (always last)
567  tabBar->setCurrentIndex(tabBar->count()-1);
568}
569
570void MainUI::on_actionClose_triggered(){
571  if(tabBar->count() > 1){
572    if(QMessageBox::Yes != QMessageBox::question(this, tr("Verify Quit"), tr("You have multiple tabs open. Are you sure you want to quit?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes ) ){
573      return;
574    }
575  }
576  qDebug() << "Closing Down...";
577  this->close();
578}
579
580void MainUI::on_actionView_Hidden_Files_triggered(){
581  if(ui->actionView_Hidden_Files->isChecked()){
582    fsmod->setFilter( QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Hidden );
583    snapmod->setFilter( QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Hidden );
584  }else{
585    fsmod->setFilter( QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs );
586    snapmod->setFilter( QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs );
587  }
588  //Now save this setting for later
589  settings->setValue("showhidden", ui->actionView_Hidden_Files->isChecked());
590  loadDirectory(); //Reload
591}
592
593void MainUI::goToBookmark(QAction *act){
594  if(act==ui->actionManage_Bookmarks){
595    BMMDialog dlg(this);
596      dlg.loadSettings(settings);
597      dlg.exec();
598    RebuildBookmarksMenu();
599  }else{
600    setCurrentDir(act->whatsThis());
601  }
602}
603
604void MainUI::goToDevice(QAction *act){
605  if(act==ui->actionScan){
606    RebuildDeviceMenu();
607  }else{
608    setCurrentDir(act->whatsThis());
609  }
610}
611
612void MainUI::viewModeChanged(bool active){
613  if(!active){ return; } //on every view change, all 3 radio buttons will call this function - only run this once though
614  if(radio_view_details->isChecked()){
615    ui->tree_dir_widget->setVisible(true);
616    ui->list_dir_widget->setVisible(false);
617        settings->setValue("viewmode","details");
618  }else if(radio_view_list->isChecked()){
619    ui->tree_dir_widget->setVisible(false);
620    ui->list_dir_widget->setVisible(true);
621    ui->list_dir_widget->setViewMode( QListView::ListMode );
622        settings->setValue("viewmode","list");
623  }else{  //icons
624    ui->tree_dir_widget->setVisible(false);
625    ui->list_dir_widget->setVisible(true);
626    ui->list_dir_widget->setViewMode( QListView::IconMode );
627        settings->setValue("viewmode","icons");
628  }
629  loadDirectory(); //reload current directory
630       
631}
632
633//-----------------------
634//Toolbar Actions
635//-----------------------
636void MainUI::on_actionBack_triggered(){
637  QStringList history = tabBar->tabData(tabBar->currentIndex()).toStringList();
638  if(history.length() <= 1){ return; } //need the second item
639  history.removeAt(0); //remove the first item (the current dir)
640  tabBar->setTabData(tabBar->currentIndex(), history); //re-write the saved history
641  setCurrentDir(history.first()); //go to the previous entry in the history
642}
643
644void MainUI::on_actionUpDir_triggered(){
645  QString dir =  getCurrentDir();
646    dir.chop( dir.section("/",-1).length() );
647    setCurrentDir(dir);
648}
649
650void MainUI::on_actionHome_triggered(){
651  setCurrentDir(QDir::homePath());
652}
653
654void MainUI::on_actionBookMark_triggered(){
655  QString dir = getCurrentDir();
656  bool ok = false;
657  QString name = QInputDialog::getText(this, tr("New Bookmark"), tr("Name:"), QLineEdit::Normal, dir, \
658                &ok, 0, Qt::ImhFormattedNumbersOnly | Qt::ImhUppercaseOnly | Qt::ImhLowercaseOnly);
659  if(!ok || name.isEmpty()){ return; } //cancelled
660  QStringList BM = settings->value("bookmarks",QStringList()).toStringList();
661  if(BM.filter(name+"::::").length() >0){
662    QMessageBox::warning(this, tr("Invalid Name"), tr("This bookmark name already exists. Please choose another.") );
663    QTimer::singleShot(0,this, SLOT(on_actionBookMark_triggered()));
664    return;
665  }
666  BM.append(name+"::::"+dir);
667  BM.sort(); //sort alphabetically by name
668  settings->setValue("bookmarks", BM);
669  //Now rebuild the bookmarks menu
670  RebuildBookmarksMenu();
671  ui->actionBookMark->setEnabled(false); //already bookmarked
672}
673
674//-----------------------------
675//Browser Functions
676//-----------------------------
677void MainUI::startEditDir(QWidget *old, QWidget *now){
678  if(now==currentDir){
679    //The dir edit just got focus
680    QString dir = currentDir->text();
681      dir.replace("~/", QDir::homePath()+"/");
682      currentDir->setText(dir);
683      //Try to move to the end
684      currentDir->selectAll();
685  }else if(old==currentDir){
686    QString dir = currentDir->text();
687      setCurrentDir(dir);
688  }
689}
690
691void MainUI::goToDirectory(){
692  QString dir = currentDir->text();
693  dir.replace("~/",QDir::homePath()+"/");
694  setCurrentDir(dir);
695}
696
697void MainUI::loadDirectory(){
698  //Disable the widgets
699  ui->tree_dir_widget->setEnabled(false);
700  ui->list_dir_widget->setEnabled(false);
701  ui->label_dir_stats->setText(tr("Loading..."));
702  //Load the directory contents and fill the widgets
703  QDir dir(getCurrentDir());
704  QFileInfoList list;
705  if(ui->actionView_Hidden_Files->isChecked()){ list = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::Hidden | QDir::AllEntries, QDir::Name | QDir::DirsFirst | QDir::IgnoreCase | QDir::LocaleAware); }
706  else{ list = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries, QDir::Name | QDir::DirsFirst | QDir::IgnoreCase | QDir::LocaleAware); }
707  //Clear the widgets
708  ui->tree_dir_widget->clear();
709  ui->list_dir_widget->clear();
710  //reset the list widget icons sizes before adding items
711  if(!radio_view_details->isChecked()){ ui->list_dir_widget->setGridSize(QSize()); } //reset the grid
712  if(radio_view_list->isChecked()){ ui->list_dir_widget->setIconSize( QSize(22,22) ); }
713  else{ ui->list_dir_widget->setIconSize( QSize(32,32) ); }
714  //Now fill the widgets
715  int longname=0;
716  for(int i=0; i<list.length(); i++){
717    if(list[i].fileName().length() > longname){ longname=list[i].fileName().length(); }
718    //Get the appropriate icon
719    QIcon ico;
720    if(list[i].isDir()){ ico = LXDG::findIcon("folder",""); }
721    else if(list[i].isExecutable()){ ico = LXDG::findIcon("application-x-executable",""); }
722    else if(list[i].suffix()=="png" || list[i].suffix()=="jpg"){ ico = QIcon(list[i].absoluteFilePath()); }
723    else{ ico = LXDG::findMimeIcon(list[i].suffix()); }
724    //Add it to the widgets
725    if(radio_view_details->isChecked()){
726      QString sz;
727      if(!list[i].isDir()){ sz = bytesToText(list[i].size()); }
728      QTreeWidgetItem *it = new QTreeWidgetItem(QStringList() << list[i].fileName() << sz << list[i].lastModified().toString(Qt::DefaultLocaleShortDate) ); //add other info columns here later
729      it->setIcon(0,ico);
730      ui->tree_dir_widget->addTopLevelItem(it);
731      if(i==0){ ui->tree_dir_widget->setCurrentItem(it); }
732    }else{
733      ui->list_dir_widget->addItem( new QListWidgetItem( ico, list[i].fileName() ) );
734      if(i==0){ ui->list_dir_widget->setCurrentRow(0); }
735    }
736    QApplication::processEvents();
737  }
738  //Make sure the items are the proper size
739  if( list.length() > 0 ){
740    if( radio_view_details->isChecked() ){ for(int i=0; i<3; i++){ ui->tree_dir_widget->resizeColumnToContents(i); } }
741    //else{}
742  }
743  //Re-enable the widgets
744  ui->tree_dir_widget->setEnabled(true);
745  ui->list_dir_widget->setEnabled(true);
746  //Reset the keyboard focus back to the widget if necessary
747  if(keepFocus){
748    if(radio_view_details->isChecked()){ ui->tree_dir_widget->setFocus(); }
749    else{ ui->list_dir_widget->setFocus(); }
750  }
751  if(isUserWritable){ ui->label_dir_stats->setText(""); }
752  else{ ui->label_dir_stats->setText(tr("Limited Access Directory")); }
753}
754
755void MainUI::on_tool_addToDir_clicked(){
756  bool ok = false;
757  QString newdir = QInputDialog::getText(this, tr("New Directory"), tr("Name:"), QLineEdit::Normal, "", \
758                &ok, 0, Qt::ImhFormattedNumbersOnly | Qt::ImhUppercaseOnly | Qt::ImhLowercaseOnly);
759  if(!ok || newdir.isEmpty()){ return; }
760  QString full = getCurrentDir();
761  if(!full.endsWith("/")){ full.append("/"); }
762  QDir dir(full); //open the current dir
763  full.append(newdir); //append the new name to the current dir
764  //Verify that the new dir does not already exist
765  if(dir.exists(full)){
766    QMessageBox::warning(this, tr("Invalid Name"), tr("A file or directory with that name already exists! Please pick a different name."));
767    QTimer::singleShot(0,this, SLOT(on_tool_addToDir_clicked()) ); //repeat this function
768  }else{
769    if(!dir.mkdir(newdir) ){
770      QMessageBox::warning(this, tr("Error Creating Directory"), tr("The directory could not be created. Please ensure that you have the proper permissions to modify the current directory."));
771    }
772  }
773}
774
775void MainUI::tabChanged(int tab){
776  //Load the directory contained in the new tab
777  qDebug() << "Change to Tab:" << tab << tabBar->tabText(tab);
778  QString dir = tabBar->tabWhatsThis(tab); //get the full directory
779  setCurrentDir(dir); //display this as the current dir
780}
781
782void MainUI::tabClosed(int tab){
783  if(tabBar->count()==1){ return; } //Can't close the only tab
784  if(tab < 0){ tab = tabBar->currentIndex(); }
785  //Remove the tab (will automatically move to a different one);
786  qDebug() << "Closing tab:" << tab << tabBar->tabText(tab);
787  tabBar->removeTab(tab);
788  tabBar->setVisible( tabBar->count() > 1 );
789}
790
791void MainUI::prevTab(){
792  int cur = tabBar->currentIndex();
793  if(cur == 0){ tabBar->setCurrentIndex( tabBar->count()-1 ); }
794  else{ tabBar->setCurrentIndex( cur-1 ); }
795}
796
797void MainUI::nextTab(){
798  int cur = tabBar->currentIndex();
799  if(cur == (tabBar->count()-1) ){ tabBar->setCurrentIndex(0); }
800  else{ tabBar->setCurrentIndex( cur+1 ); }     
801}
802
803void MainUI::ItemRun(const QModelIndex &index){
804  //This is called when the user double clicks a file/directory
805  QString val = fsmod->filePath(index).section("/",-1);
806  QString itemPath = getCurrentDir();
807  if( !itemPath.endsWith("/")){ itemPath.append("/"); }
808  itemPath.append(val);
809  if(fsmod->isDir(index)){
810    setCurrentDir( itemPath );
811  }else{
812    //Must be a file, try to run it
813    QProcess::startDetached("lumina-open "+itemPath);
814  }
815}
816
817void MainUI::ItemRun(QTreeWidgetItem *item){
818  //This is called when the user double clicks a file/directory
819  QString val = item->text(0);
820  QString itemPath = getCurrentDir();
821  if( !itemPath.endsWith("/")){ itemPath.append("/"); }
822  itemPath.append(val);
823  if(QFileInfo(itemPath).isDir()){
824    setCurrentDir( itemPath );
825  }else{
826    //Must be a file, try to run it
827    QProcess::startDetached("lumina-open "+itemPath);
828  }
829}
830
831void MainUI::ItemRun(QListWidgetItem *item){
832  //This is called when the user double clicks a file/directory
833  QString val = item->text();
834  QString itemPath = getCurrentDir();
835  if( !itemPath.endsWith("/")){ itemPath.append("/"); }
836  itemPath.append(val);
837  if(QFileInfo(itemPath).isDir()){
838    setCurrentDir( itemPath );
839  }else{
840    //Must be a file, try to run it
841    QProcess::startDetached("lumina-open "+itemPath);
842  }
843}
844
845void MainUI::OpenContextMenu(const QPoint &pt){
846  if(radio_view_details->isChecked()){ 
847    QTreeWidgetItem *it = ui->tree_dir_widget->itemAt(pt);
848    if(it==0){ return;}
849    else{ CItem = it->text(0); }
850  }else{ 
851    QListWidgetItem *it = ui->list_dir_widget->itemAt(pt);
852    if(it==0){ return; }
853    else{ CItem = it->text(); }
854  }
855  QString cdir = getCurrentDir();
856  if(!cdir.endsWith("/")){ cdir.append("/"); }
857  CItem.prepend(cdir);
858    //Create the context menu
859    contextMenu->clear();
860    QFileInfo info(CItem);
861    if(info.isDir()){
862      contextMenu->addAction(LXDG::findIcon("tab-new-background",""), tr("Open in new tab"), this, SLOT(OpenDir()) );
863    }else{
864      contextMenu->addAction(LXDG::findIcon("quickopen-file",""), tr("Open"), this, SLOT(OpenItem()) );
865      contextMenu->addAction(tr("Open With..."), this, SLOT(OpenItemWith()) );
866    }
867    contextMenu->addAction(LXDG::findIcon("edit-rename",""), tr("Rename"), this, SLOT(RenameItem()) )->setEnabled(info.isWritable());
868    contextMenu->addSeparator();
869  //Now add the general selection options
870  contextMenu->addAction(LXDG::findIcon("edit-cut",""), tr("Cut Selection"), this, SLOT(CutItems()) )->setEnabled(info.isWritable());
871  contextMenu->addAction(LXDG::findIcon("edit-copy",""), tr("Copy Selection"), this, SLOT(CopyItems()) );
872  contextMenu->addAction(LXDG::findIcon("edit-paste",""), tr("Paste"), this, SLOT(PasteItems()) )->setEnabled(QApplication::clipboard()->mimeData()->hasFormat("x-special/lumina-copied-files") && isUserWritable);
873  contextMenu->addSeparator();
874  contextMenu->addAction(LXDG::findIcon("edit-delete",""), tr("Delete Selection"), this, SLOT(RemoveItem()) )->setEnabled(info.isWritable());
875  //Now show the menu
876  if(radio_view_details->isChecked()){
877    contextMenu->popup(ui->tree_dir_widget->mapToGlobal(pt));
878  }else{
879    contextMenu->popup(ui->list_dir_widget->mapToGlobal(pt));
880  }
881}
882
883//-------------------------------
884//Slideshow Functions
885//-------------------------------
886void MainUI::showNewPicture(){
887  if( !ui->label_image->isVisible() ){ return; } //don't update if not visible - can cause strange resizing issues
888  QString file = getCurrentDir();
889  if(!file.endsWith("/")){ file.append("/"); }
890  file.append(ui->combo_image_name->currentText());
891  if(!file.endsWith(".png") && !file.endsWith(".jpg")){ return; } //invalid - no change
892  //qDebug() << "Show Image:" << file;
893  QPixmap pix(file);
894  if(pix.size().width() > ui->label_image->contentsRect().width() || pix.size().height() > ui->label_image->contentsRect().height()){ 
895    pix = pix.scaled(ui->label_image->contentsRect().size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); 
896  }
897  ui->label_image->setPixmap(pix);
898  //Now set/load the buttons
899  ui->tool_image_goBegin->setEnabled(ui->combo_image_name->currentIndex()>0);
900  ui->tool_image_goPrev->setEnabled(ui->combo_image_name->currentIndex()>0);
901  ui->tool_image_goEnd->setEnabled(ui->combo_image_name->currentIndex()<(ui->combo_image_name->count()-1));
902  ui->tool_image_goNext->setEnabled(ui->combo_image_name->currentIndex()<(ui->combo_image_name->count()-1));
903  ui->label_image_index->setText( QString::number(ui->combo_image_name->currentIndex()+1)+"/"+QString::number(ui->combo_image_name->count()) );
904}
905
906void MainUI::firstPicture(){
907  ui->combo_image_name->setCurrentIndex(0);
908}
909
910void MainUI::prevPicture(){
911  ui->combo_image_name->setCurrentIndex( ui->combo_image_name->currentIndex()-1 );
912}
913
914void MainUI::nextPicture(){
915  ui->combo_image_name->setCurrentIndex( ui->combo_image_name->currentIndex()+1 );
916}
917
918void MainUI::lastPicture(){
919  ui->combo_image_name->setCurrentIndex( ui->combo_image_name->count()-1 );
920}
921
922//----------------------------------
923//ZFS Restore Functions
924//----------------------------------
925void MainUI::snapshotLoaded(){
926  ui->tree_zfs_dir->resizeColumnToContents(0);
927}
928
929void MainUI::showSnapshot(){
930  ui->tool_zfs_prevSnap->setEnabled(ui->slider_zfs_snapshot->value()!=1);
931  ui->tool_zfs_nextSnap->setEnabled(ui->slider_zfs_snapshot->value()!=ui->slider_zfs_snapshot->maximum());
932  ui->label_zfs_snap->setText( snapDirs[ui->slider_zfs_snapshot->value()-1].section("/.zfs/snapshot/",1,1).section("/",0,0) );
933  //Load the dir contents
934  ui->tree_zfs_dir->setRootIndex(snapmod->setRootPath(snapDirs[ui->slider_zfs_snapshot->value()-1]));
935}
936
937void MainUI::prevSnapshot(){
938  ui->slider_zfs_snapshot->setValue(ui->slider_zfs_snapshot->value()-1);
939}
940
941void MainUI::nextSnapshot(){
942  ui->slider_zfs_snapshot->setValue(ui->slider_zfs_snapshot->value()+1);
943}
944
945void MainUI::restoreItems(){
946   //Get the selected items
947   QStringList sel = getSelectedItems();
948   QModelIndexList items = ui->tree_zfs_dir->selectionModel()->selectedIndexes();
949   for(int i=0; i<items.length(); i++){
950     sel << snapmod->filePath(items[i]).section("/",-1);
951   }
952   sel.removeDuplicates();
953   if(sel.isEmpty()){ return; } //nothing selected
954   if(!checkUserPerms()){ return; }
955   //Get the directories
956   QString snapdir = snapDirs[ui->slider_zfs_snapshot->value()-1];
957   QString basedir = getCurrentDir();
958   if(!basedir.endsWith("/")){ basedir.append("/"); }
959   if(!snapdir.endsWith("/")){ snapdir.append("/"); }
960   //Fill out the lists appropriately
961   QStringList resto;
962   qDebug() << "Items Selected:" << sel;
963   for(int i=0; i<sel.length(); i++){
964     resto << basedir+sel[i];
965     sel[i] = snapdir+sel[i];
966   }
967   qDebug() << "Restore Items:" << sel << "\n" << resto;
968   //Restore the items
969   FODialog dlg(this);
970        dlg.setOverwrite(ui->check_zfs_overwrite->isChecked());
971        dlg.RestoreFiles(sel, resto);
972   dlg.exec();
973   if(dlg.noerrors){
974     QMessageBox::information(this, tr("Success"), tr("Successfully restored selection") );
975   }
976}
977
978//----------------------------
979// Multimedia Player
980//----------------------------
981void MainUI::playerStart(){
982  if(ui->stackedWidget->currentWidget()!=ui->page_audioPlayer){ return; } //don't play if not in the player
983 
984  if(mediaObj->state()==Phonon::PausedState){
985    mediaObj->play();
986  }else if(mediaObj->state()==Phonon::StoppedState || mediaObj->state()==Phonon::ErrorState || (playerFile->fileName().section("/",-1) != ui->combo_player_list->currentText()) || playerFile->isOpen() ){
987    mediaObj->stop();
988    //Get the selected file path
989    QString filePath = getCurrentDir();
990    if(!filePath.endsWith("/")){ filePath.append("/"); }
991    filePath.append( ui->combo_player_list->currentText() );
992    if(playerFile->isOpen()){ playerFile->close(); }
993    playerFile->setFileName(filePath);
994    if(playerFile->open(QIODevice::ReadOnly)){
995      mediaObj->setCurrentSource( playerFile );
996      playerSlider->setMediaObject(mediaObj);
997      mediaObj->play();
998    }
999  }
1000}
1001
1002void MainUI::playerStop(){
1003  mediaObj->stop();
1004}
1005
1006void MainUI::playerPause(){
1007  mediaObj->pause();
1008}
1009
1010void MainUI::playerNext(){
1011  ui->combo_player_list->setCurrentIndex( ui->combo_player_list->currentIndex()+1);
1012}
1013
1014void MainUI::playerPrevious(){
1015  ui->combo_player_list->setCurrentIndex( ui->combo_player_list->currentIndex()-1);     
1016}
1017
1018void MainUI::playerFinished(){
1019  playerFile->close();
1020  if(ui->combo_player_list->currentIndex()<(ui->combo_player_list->count()-1) && ui->check_player_gotonext->isChecked()){
1021    ui->combo_player_list->setCurrentIndex( ui->combo_player_list->currentIndex()+1 );
1022  }else{
1023    ui->label_player_novideo->setText(tr("Finished"));
1024  }
1025}
1026
1027void MainUI::playerStateChanged(Phonon::State newstate, Phonon::State oldstate){
1028  //This function keeps track up updating the visuals of the player
1029  bool running = false;
1030  bool showVideo = false;
1031  QString msg;
1032  switch(newstate){
1033    case Phonon::LoadingState:
1034        running=true;
1035        ui->label_player_novideo->setText(tr("Loading File..."));
1036        break;
1037    case Phonon::PlayingState:
1038        running=true;
1039        showVideo = mediaObj->hasVideo();
1040        msg = mediaObj->metaData(Phonon::TitleMetaData).join(" ");
1041        if(msg.simplified().isEmpty()){ msg = playerFile->fileName().section("/",-1); }
1042        ui->label_player_novideo->setText(tr("Playing:")+"\n"+msg);
1043        break;
1044    case Phonon::BufferingState:
1045        running=true;
1046        showVideo=true; //don't blank the screen
1047        break;
1048    case Phonon::PausedState:
1049        showVideo=videoDisplay->isVisible(); //don't change the screen
1050        break;
1051    case Phonon::StoppedState:
1052        if(oldstate==Phonon::LoadingState){ mediaObj->play(); }
1053        else{ ui->label_player_novideo->setText(tr("Stopped")); }
1054        break;
1055    case Phonon::ErrorState:
1056        ui->label_player_novideo->setText(tr("Error Playing File")+"\n("+mediaObj->errorString()+")");
1057        break;
1058  }
1059  ui->tool_player_play->setVisible(!running);
1060  ui->tool_player_pause->setVisible(running);
1061  ui->tool_player_stop->setEnabled(running);
1062  ui->label_player_novideo->setVisible(!showVideo);
1063  videoDisplay->setVisible(showVideo);
1064}
1065
1066void MainUI::playerVideoAvailable(bool showVideo){
1067  ui->label_player_novideo->setVisible(!showVideo);
1068  videoDisplay->setVisible(showVideo); 
1069}
1070
1071void MainUI::playerTimeChanged(qint64 ctime){
1072  if(playerTTime=="0:00" || playerTTime.isEmpty()){ playerTTime = msToText(mediaObj->totalTime()); } //only calculate as necessary
1073  //qDebug() << "Time:" << msToText(ctime) << playerTTime << mediaObj->isSeekable() << mediaObj->hasVideo();
1074  ui->label_player_runstats->setText( msToText(ctime)+"/"+playerTTime );
1075}
1076
1077void MainUI::playerFileChanged(){
1078  ui->tool_player_next->setEnabled( ui->combo_player_list->count() > (ui->combo_player_list->currentIndex()+1) );       
1079  ui->tool_player_prev->setEnabled( (ui->combo_player_list->currentIndex()-1) >= 0 );
1080  if(ui->stackedWidget->currentWidget()!=ui->page_audioPlayer){ return; } //don't play if not in the player
1081  //If one is playing, so ahead and start playing the new selection
1082  if(playerFile->isOpen() || ui->check_player_gotonext->isChecked() ){
1083    QTimer::singleShot(0,this,SLOT(playerStart()));
1084  }
1085}
1086
1087//----------------------------------
1088// Context Menu Actions
1089//----------------------------------
1090void MainUI::OpenItem(){
1091  if(CItem.isEmpty()){ return; }
1092  qDebug() << "Opening File:" << CItem;
1093  QProcess::startDetached("lumina-open \""+CItem+"\"");
1094}
1095
1096void MainUI::OpenItemWith(){
1097  if(CItem.isEmpty()){ return; }
1098  qDebug() << "Opening File:" << CItem;
1099  QProcess::startDetached("lumina-open -select \""+CItem+"\""); 
1100}
1101
1102void MainUI::OpenDir(){
1103  if(CItem.isEmpty()){ return; }
1104  OpenDirs(QStringList() << CItem);             
1105}
1106
1107void MainUI::RemoveItem(){
1108  //Only let this run if viewing the browser page
1109  if(ui->stackedWidget->currentWidget()!=ui->page_browser){ return; }
1110   if(!checkUserPerms()){ return; }
1111   //Get the selected items
1112   QStringList sel, names;
1113   names = getSelectedItems();
1114   //QModelIndexList items = ui->tree_dir_view->selectionModel()->selectedIndexes();
1115   QString baseDir = getCurrentDir();
1116   if(!baseDir.endsWith("/")){ baseDir.append("/"); }
1117   for(int i=0; i<names.length(); i++){
1118     sel << baseDir+names[i];
1119   }
1120   if(sel.isEmpty()){ return; } //nothing selected
1121  //Verify permanent removal of file/dir
1122  if(QMessageBox::Yes != QMessageBox::question(this, tr("Verify Removal"), tr("WARNING: This will permanently delete the file(s) from the system!")+"\n"+tr("Are you sure you want to continue?")+"\n\n"+names.join("\n"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){
1123    return; //cancelled
1124  }
1125  //Now remove the file/dir
1126  qDebug() << "Delete: "<<sel;
1127  FODialog dlg(this);
1128    dlg.RemoveFiles(sel);
1129    dlg.exec();
1130}
1131
1132void MainUI::RenameItem(){
1133  //Only let this run if viewing the browser page
1134  if(ui->stackedWidget->currentWidget()!=ui->page_browser){ return; }
1135  if(CItem.isEmpty()){ return; }
1136  if(!checkUserPerms()){ return; }
1137  QString fname = CItem;
1138  QString path = fname;
1139    fname = fname.section("/",-1); //turn this into just the file name
1140    path.chop(fname.length());  //turn this into the base directory path (has a "/" at the end)
1141  //Now prompt for the new filename
1142  bool ok = false;
1143  QString nname = QInputDialog::getText(this, tr("Rename File"),tr("New Name:"), QLineEdit::Normal, fname, &ok);
1144  if(!ok || nname.isEmpty()){ return; } //cancelled
1145  //Now check for a file extension and add it if necessary
1146  QString oext = fname.section(".",-1);
1147    if(oext==fname){ oext.clear(); } //no extension
1148  QString next = nname.section(".",-1);
1149    if(next==nname){ next.clear(); } //no extension
1150  if(next.isEmpty() && !oext.isEmpty()){
1151    nname.append( "."+oext );
1152  }
1153  //Check if this filename already exists
1154  bool overwrite = QFile::exists(path+nname);
1155  if(overwrite){
1156    if(QMessageBox::Yes != QMessageBox::question(this, tr("Overwrite File?"), tr("An existing file with the same name will be replaced. Are you sure you want to proceed?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){
1157      return; //cancelled
1158    }
1159  }
1160  //Now perform the move
1161  qDebug() << "Rename:" << path+fname << "->" << path+nname;
1162  FODialog dlg(this);
1163    dlg.setOverwrite(overwrite);
1164    dlg.MoveFiles(QStringList() << path+fname, QStringList() << path+nname);
1165    dlg.exec();
1166}
1167
1168void MainUI::CutItems(){
1169  //Only let this run if viewing the browser page
1170  if(ui->stackedWidget->currentWidget()!=ui->page_browser){ return; }
1171  if(!checkUserPerms()){ return; }
1172  //Get all the selected Items
1173  QStringList sel = getSelectedItems();
1174  if(sel.isEmpty()){ return; } //nothing selected
1175  qDebug() << "Cut Items:" << sel;
1176  //Format the data string
1177  for(int i=0; i<sel.length(); i++){
1178    sel[i] = sel[i].prepend("cut::::");
1179  }
1180 
1181  //Now save that data to the global clipboard
1182  QMimeData *dat = new QMimeData;
1183        dat->clear();
1184        dat->setData("x-special/lumina-copied-files", sel.join("\n").toLocal8Bit());
1185  QApplication::clipboard()->clear();
1186  QApplication::clipboard()->setMimeData(dat);
1187}
1188
1189void MainUI::CopyItems(){
1190  //Only let this run if viewing the browser page
1191  if(ui->stackedWidget->currentWidget()!=ui->page_browser){ return; }
1192  //Get all the selected Items
1193  QStringList sel = getSelectedItems();
1194  if(sel.isEmpty()){ return; } //nothing selected
1195  qDebug() << "Copy Items:" << sel;
1196  //Format the data string
1197  for(int i=0; i<sel.length(); i++){
1198    sel[i] = sel[i].prepend("copy::::");
1199  }
1200  //Now save that data to the global clipboard
1201  QMimeData *dat = new QMimeData;
1202        dat->clear();
1203        dat->setData("x-special/lumina-copied-files", sel.join("\n").toLocal8Bit());
1204  QApplication::clipboard()->clear();
1205  QApplication::clipboard()->setMimeData(dat); 
1206}
1207
1208void MainUI::PasteItems(){
1209  //Only let this run if viewing the browser page
1210  if(ui->stackedWidget->currentWidget()!=ui->page_browser){ return; }
1211  const QMimeData *dat = QApplication::clipboard()->mimeData();
1212  if(!dat->hasFormat("x-special/lumina-copied-files")){ return; } //nothing to paste
1213  if(!checkUserPerms()){ return; }
1214  QStringList cut, copy, newcut, newcopy;
1215  QStringList raw = QString(dat->data("x-special/lumina-copied-files")).split("\n");
1216  QString base = getCurrentDir();
1217  if(!base.endsWith("/")){ base.append("/"); }
1218  for(int i=0; i<raw.length(); i++){
1219    if(raw[i].startsWith("cut::::")){ 
1220        cut << raw[i].section("::::",1,50);
1221        newcut << base+raw[i].section("::::",1,50).section("/",-1);
1222    }
1223    else if(raw[i].startsWith("copy::::")){ 
1224        copy << raw[i].section("::::",1,50); 
1225        newcopy<< base+raw[i].section("::::",1,50).section("/",-1);
1226    }
1227  }
1228  bool errs = false;
1229  //Perform the copy/move operations
1230  if(!copy.isEmpty()){ 
1231    qDebug() << "Paste Copy:" << copy << "->" << newcopy;
1232    FODialog dlg(this);
1233      dlg.CopyFiles(copy, newcopy);
1234      dlg.exec();
1235      errs = errs || !dlg.noerrors;
1236  }
1237  if(!cut.isEmpty()){
1238    qDebug() << "Paste Cut:" << cut << "->" << newcut;
1239    FODialog dlg(this);
1240      dlg.MoveFiles(cut, newcut);
1241      dlg.exec();
1242      errs = errs || !dlg.noerrors;
1243  }
1244  //Modify the clipboard appropriately
1245  if(!errs && !cut.isEmpty()){
1246    //Now clear the clipboard since those old file locations are now invalid
1247    QApplication::clipboard()->clear(); 
1248    if(!copy.isEmpty()){
1249      //There were also files copied: save those files back into the clipboard
1250       QMimeData *dat = new QMimeData;
1251        dat->clear();
1252        dat->setData("x-special/lumina-copied-files", raw.filter("copy::::").join("\n").toLocal8Bit());
1253        QApplication::clipboard()->setMimeData(dat);
1254    }
1255  }
1256       
1257}
Note: See TracBrowser for help on using the repository browser.