1 //===========================================
2 //  Lumina-DE source code
3 //  Copyright (c) 2014-2015, 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 
10 #include <QMenu>
11 
12 #include "gitCompat.h"
13 #include "gitWizard.h"
14 
15 #include <LUtils.h>
16 #include <LDesktopUtils.h>
17 #include <ExternalProcess.h>
18 #include <LFileInfo.h>
19 
20 #define DEBUG 0
21 bool rootmode = false;
22 
MainUI()23 MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI){
24   //for Signal/slot we must register the Typedef of QFileInfoList
25   //qRegisterMetaType<QFileInfoList>("QFileInfoList");
26   qRegisterMetaType< LFileInfoList >("LFileInfoList");
27   //just to silence/fix some Qt connect warnings in QtConcurrent
28   //qRegisterMetaType< QVector<int> >("QVector<int>");
29   //qRegisterMetaType< QList<QPersistentModelIndex> >("QList<QPersistentModelIndex>");
30   waitingToClose = false;
31   //put if statement here to check if running as root
32   rootmode = (getuid()==0);
33 
34   ui->setupUi(this);
35   if(DEBUG){ qDebug() << "Initilization:"; }
36   settings = LUtils::openSettings("lumina-desktop", "lumina-fm", this);
37 
38   //Reset the UI to the previously used size (if possible)
39 QSize orig = settings->value("preferences/MainWindowSize", QSize()).toSize();
40   if(!orig.isEmpty() && orig.isValid()){
41     //Make sure the old size is larger than the default size hint
42     if(orig.width() < this->sizeHint().width()){ orig.setWidth(this->sizeHint().width()); }
43     if(orig.height() < this->sizeHint().height()){ orig.setHeight(this->sizeHint().height()); }
44     //Also ensure the old size is smaller than the current screen size
45     QSize screen = QApplication::desktop()->availableGeometry(this).size();
46     if(orig.width() > screen.width()){ orig.setWidth(screen.width()); }
47     if(orig.height() > screen.height()){ orig.setHeight(screen.height()); }
48     //Now resize the window
49     this->resize(orig);
50   }
51   //initialize the non-ui widgets
52   if(DEBUG){ qDebug() << " - Tab Bar Setup"; }
53   tabBar = new QTabBar(this);
54     tabBar->setTabsClosable(true);
55     tabBar->setMovable(true); //tabs are independant - so allow the user to sort them
56     tabBar->setShape(QTabBar::RoundedNorth);
57     tabBar->setFocusPolicy(Qt::NoFocus);
58     static_cast<QBoxLayout*>(ui->centralwidget->layout())->insertWidget(0,tabBar);
59   if(DEBUG){ qDebug() << " - Threading"; }
60   workThread = new QThread;
61     workThread->setObjectName("Lumina-fm filesystem worker");
62   worker = new DirData();
63     worker->zfsavailable = LUtils::isValidBinary("zfs");
64     //connect(worker, SIGNAL(DirDataAvailable(QString, QString, LFileInfoList)), this, SLOT(DirDataAvailable(QString, QString, LFileInfoList)) );
65     connect(worker, SIGNAL(SnapshotDataAvailable(QString, QString, QStringList)), this, SLOT(SnapshotDataAvailable(QString, QString, QStringList)) );
66     worker->moveToThread(workThread);
67   if(DEBUG){ qDebug() << " - Context Menu"; }
68   contextMenu = new QMenu(this);
69   radio_view_details = new QRadioButton(tr("Detailed List"), this);
70   radio_view_list = new QRadioButton(tr("Basic List"), this);
71   //radio_view_tabs = new QRadioButton(tr("Prefer Tabs"), this);
72   //radio_view_cols = new QRadioButton(tr("Prefer Columns"), this);
73   ui->menuView_Mode->clear();
74   //ui->menuGroup_Mode->clear();
75   detWA = new QWidgetAction(this);
76     detWA->setDefaultWidget(radio_view_details);
77   listWA = new QWidgetAction(this);
78     listWA->setDefaultWidget(radio_view_list);
79   //tabsWA = new QWidgetAction(this);
80     //tabsWA->setDefaultWidget(radio_view_tabs);
81   //colsWA = new QWidgetAction(this);
82     //colsWA->setDefaultWidget(radio_view_cols);
83     ui->menuView_Mode->addAction(detWA);
84     ui->menuView_Mode->addAction(listWA);
85     //ui->menuGroup_Mode->addAction(tabsWA);
86     //ui->menuGroup_Mode->addAction(colsWA);
87   if(DEBUG){ qDebug() << " - sort Menu"; }
88   menuSort_Mode = new QMenu(this);
89   radio_sort_name = new QRadioButton(tr("Sort by Name"), this);
90   radio_sort_size = new QRadioButton(tr("Sort by Size"), this);
91   radio_sort_type = new QRadioButton(tr("Sort by Type"), this);
92   radio_sort_datemod = new QRadioButton(tr("Sort by Date Modified"), this);
93   radio_sort_datecre = new QRadioButton(tr("Sort by Date Created"), this);
94   ui->menuSort_Mode->clear();
95   sortnameA = new QWidgetAction(this);
96     sortnameA->setDefaultWidget(radio_sort_name);
97   sortsizeA = new QWidgetAction(this);
98     sortsizeA->setDefaultWidget(radio_sort_size);
99   sorttypeA = new QWidgetAction(this);
100     sorttypeA->setDefaultWidget(radio_sort_type);
101   sortdateMA = new QWidgetAction(this);
102     sortdateMA->setDefaultWidget(radio_sort_datemod);
103   sortdateCA = new QWidgetAction(this);
104     sortdateCA->setDefaultWidget(radio_sort_datecre);
105 
106 
107     ui->menuSort_Mode->addAction(sortnameA);
108     ui->menuSort_Mode->addAction(sortsizeA);
109     ui->menuSort_Mode->addAction(sorttypeA);
110     ui->menuSort_Mode->addAction(sortdateMA);
111     ui->menuSort_Mode->addAction(sortdateCA);
112 
113   //Setup the pages
114   //ui->BrowserLayout->clear();
115   ui->page_player->setLayout(new QVBoxLayout());
116   ui->page_image->setLayout(new QVBoxLayout());
117   MW = new MultimediaWidget(this);
118   SW = new SlideshowWidget(this);
119   ui->page_player->layout()->addWidget(MW);
120   ui->page_image->layout()->addWidget(SW);
121 
122   //Setup any specialty keyboard shortcuts
123   if(DEBUG){ qDebug() << " - Keyboard Shortcuts"; }
124   nextTabLShort = new QShortcut( QKeySequence(tr("Shift+Left")), this);
125   nextTabRShort = new QShortcut( QKeySequence(tr("Shift+Right")), this);
126   togglehiddenfilesShort = new QShortcut( QKeySequence(tr("Ctrl+H")), this);
127   focusDirWidgetShort = new QShortcut( QKeySequence(tr("Ctrl+L")), this);
128   //toggledirtreepaneShort = new QShortcut( QKeySequence(tr("Ctrl+P")), this);
129 
130   //Finish loading the interface
131   workThread->start();
132   if(DEBUG){ qDebug() << " - Icons"; }
133   setupIcons();
134   if(DEBUG){ qDebug() << " - Connections"; }
135   setupConnections();
136   if(DEBUG){ qDebug() << " - Settings"; }
137   loadSettings();
138   if(DEBUG){ qDebug() << " - Bookmarks"; }
139   RebuildBookmarksMenu();
140   if(DEBUG){ qDebug() << " - Devices"; }
141   RebuildDeviceMenu();
142   //Make sure we start on the browser page
143   TRAY = new TrayUI(this);
144   connect(TRAY, SIGNAL(JobsFinished()), this, SLOT(TrayJobsFinished()) );
145   if(DEBUG){ qDebug() << " - Done with init"; }
146   ui->actionOpen_as_Root->setVisible(LUtils::isValidBinary("qsudo"));
147   ui->transferTreeView->setVisible(false);
148 }
149 
~MainUI()150 MainUI::~MainUI(){
151   for(int i=0; i<DWLIST.length(); i++){
152     DWLIST[i]->cleanup();
153   }
154   workThread->quit();
155   //Also ensure the work thread is stopped
156 //  workThread->wait();
157 }
158 
OpenDirs(QStringList dirs)159 void MainUI::OpenDirs(QStringList dirs){
160   //Now open the dirs
161   if(dirs.isEmpty()){ dirs << QDir::homePath(); }
162   QStringList invalid;
163   for(int i=0; i<dirs.length(); i++){
164     if(dirs[i].simplified().isEmpty()){ continue; }
165     //Open this directory in a viewer
166     if(dirs[i].endsWith("/")){ dirs[i].chop(1); }
167     if(!QFile::exists(dirs[i])){ invalid << dirs[i]; continue; }
168     if(DEBUG){ qDebug() << "Open Directory:" << dirs[i]; }
169     ///Get a new Unique ID
170     int id = 0;
171     for(int j=0; j<DWLIST.length(); j++){
172       if(DWLIST[j]->id().section("-",1,1).toInt() >= id){ id = DWLIST[j]->id().section("-",1,1).toInt()+1; }
173     }
174     //Create the new DirWidget
175     DirWidget *DW = new DirWidget("DW-"+QString::number(id), settings, this);
176     DW->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
177     ui->BrowserLayout->addWidget(DW);
178     DWLIST << DW;
179     //Connect the signals/slots for it
180     connect(DW, SIGNAL(OpenDirectories(QStringList)), this, SLOT(OpenDirs(QStringList)) );
181     //connect(DW, SIGNAL(LoadDirectory(QString, QString)), worker, SLOT(GetDirData(QString, QString)) );
182     connect(DW, SIGNAL(findSnaps(QString, QString)), worker, SLOT(GetSnapshotData(QString, QString)) );
183     connect(DW, SIGNAL(PlayFiles(LFileInfoList)), this, SLOT(OpenPlayer(LFileInfoList)) );
184     connect(DW, SIGNAL(ViewFiles(LFileInfoList)), this, SLOT(OpenImages(LFileInfoList)) );
185     connect(DW, SIGNAL(LaunchTerminal(QString)), this, SLOT(OpenTerminal(QString)) );
186     connect(DW, SIGNAL(CutFiles(QStringList)), this, SLOT(CutFiles(QStringList)) );
187     connect(DW, SIGNAL(CopyFiles(QStringList)), this, SLOT(CopyFiles(QStringList)) );
188     connect(DW, SIGNAL(FavoriteFiles(QStringList)), this, SLOT(FavoriteFiles(QStringList)) );
189     connect(DW, SIGNAL(RenameFiles(QStringList)), this, SLOT(RenameFiles(QStringList)) );
190     connect(DW, SIGNAL(RemoveFiles(QStringList)), this, SLOT(RemoveFiles(QStringList)) );
191     connect(DW, SIGNAL(PasteFiles(QString,QStringList)), this, SLOT(PasteFiles(QString, QStringList)) );
192     connect(DW, SIGNAL(CloseBrowser(QString)), this, SLOT(CloseBrowser(QString)) );
193     connect(DW, SIGNAL(TabNameChanged(QString,QString)), this, SLOT(TabNameChanged(QString, QString)) );
194     connect(DW, SIGNAL(treeWidgetSizeChanged(float)), this, SLOT(treeWidgetWidthChanged(float)) );
195     //Now create the tab for this
196     //if(radio_view_tabs->isChecked()){
197       int index = tabBar->addTab( LXDG::findIcon("folder-open",""), dirs[i].section("/",-1) );
198       tabBar->setTabWhatsThis( index, "DW-"+QString::number(id) );
199       tabBar->setCurrentIndex(index);
200     /*}else{
201       //Just make sure the browser tab is visible
202       bool found = false;
203       for(int i=0; i<tabBar->count() && !found; i++){
204         if(tabBar->tabWhatsThis(i)=="browser"){ tabBar->setCurrentIndex(i); found=true; }
205       }
206       if(!found){
207         //Need to create the generic Browser tab
208         int index = tabBar->addTab( LXDG::findIcon("folder-open",""), "Browser" );
209         tabBar->setTabWhatsThis( index, "browser" );
210         tabBar->setCurrentIndex(index);
211       }
212     }*/
213 
214     //Initialize the widget with the proper settings
215     if(DEBUG){ qDebug() << "Setup Dir Widget"; }
216     DW->setShowDetails(radio_view_details->isChecked() );
217     DW->setThumbnailSize(settings->value("iconsize", 32).toInt() );
218     DW->showHidden( ui->actionView_Hidden_Files->isChecked() );
219     DW->showThumbnails( ui->actionShow_Thumbnails->isChecked() );
220     //DW->showDirTreePane( ui->actionView_showDirTreePane->isChecked() );
221     DW->adjustTreeWidget( settings->value("dirTree_width", 25.0).toFloat() );
222     DW->setTreeSortMode( settings->value("sortmode","num").toInt() );
223     //Now load the directory
224     if(DEBUG){ qDebug() << "Load Directory"; }
225     DW->ChangeDir(dirs[i]); //kick off loading the directory info
226   }
227   //Update visibilities
228   tabChanged(tabBar->currentIndex());
229   tabBar->setVisible( tabBar->count() > 1 );
230   if(!invalid.isEmpty()){
231     QMessageBox::warning(this, tr("Invalid Directories"), tr("The following directories are invalid and could not be opened:")+"\n"+invalid.join(", ") );
232   }
233   //Double check that there is at least 1 dir loaded
234   //qDebug() << "OpenDirs:" << DWLIST.length() << dirs << invalid << tabBar->currentIndex();
235   if(DWLIST.isEmpty()){ OpenDirs(QStringList()); }
236   waitingToClose = false;
237   ui->menuGit->setEnabled( GIT::isAvailable() );
238   this->showNormal(); //single-instance check - make sure the window is raised again if it was minimized
239 }
240 
setupIcons()241 void MainUI::setupIcons(){
242   this->setWindowIcon( LXDG::findIcon("Insight-FileManager","") );
243 
244   //Setup all the icons using libLumina
245   // File menu
246   ui->actionNew_Window->setIcon( LXDG::findIcon("window-new","") );
247   ui->actionNew_Tab->setIcon( LXDG::findIcon("tab-new","") );
248   ui->actionSearch->setIcon( LXDG::findIcon("edit-find","") );
249   ui->actionOpen_as_Root->setIcon( LXDG::findIcon("system-file-manager-root","") );
250   ui->actionClose_Browser->setIcon( LXDG::findIcon("tab-close","") );
251   ui->actionClose->setIcon( LXDG::findIcon("application-exit","") );
252 
253   // Edit menu
254   ui->actionRename->setIcon( LXDG::findIcon("edit-rename","") );
255   ui->actionCut_Selection->setIcon( LXDG::findIcon("edit-cut","") );
256   ui->actionCopy_Selection->setIcon( LXDG::findIcon("edit-copy","") );
257   ui->actionPaste->setIcon( LXDG::findIcon("edit-paste","") );
258   ui->actionDelete_Selection->setIcon( LXDG::findIcon("edit-delete","") );
259 
260   // View menu
261   ui->actionRefresh->setIcon( LXDG::findIcon("view-refresh","") );
262   ui->menuView_Mode->setIcon( LXDG::findIcon("view-choose","") );
263   ui->menuSort_Mode->setIcon(LXDG::findIcon("list-spacing","view-list") );
264 
265   // Bookmarks menu
266   ui->actionManage_Bookmarks->setIcon( LXDG::findIcon("bookmarks-organize","") );
267   ui->actionManage_Bookmarks->setShortcut(tr("CTRL+B"));
268   ui->actionAdd_Bookmark->setIcon( LXDG::findIcon("bookmark-new","") );
269 
270   //GIT menu
271   ui->actionRepo_Status->setIcon( LXDG::findIcon("git","document-edit-verify") );
272   ui->actionClone_Repository->setIcon( LXDG::findIcon("git","download") );
273 
274   // External Devices menu
275   ui->actionScan->setIcon( LXDG::findIcon("system-search","") );
276   ui->actionScan->setShortcut(tr("CTRL+E"));
277 }
278 
279 //==========
280 //    PRIVATE
281 //==========
setupConnections()282 void MainUI::setupConnections(){
283   connect(tabBar, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)) );
284   connect(tabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(tabClosed(int)) );
285   connect(ui->menuBookmarks, SIGNAL(triggered(QAction*)), this, SLOT(goToBookmark(QAction*)) );
286   connect(ui->menuExternal_Devices, SIGNAL(triggered(QAction*)), this, SLOT(goToDevice(QAction*)) );
287 
288   //Radio Buttons
289   connect(radio_view_details, SIGNAL(toggled(bool)), this, SLOT(viewModeChanged(bool)) );
290   connect(radio_view_list, SIGNAL(toggled(bool)), this, SLOT(viewModeChanged(bool)) );
291   //connect(radio_view_tabs, SIGNAL(toggled(bool)), this, SLOT(groupModeChanged(bool)) );
292   //connect(radio_view_cols, SIGNAL(toggled(bool)), this, SLOT(groupModeChanged(bool)) );
293 
294   // Sort Buttons
295   connect(radio_sort_name, SIGNAL(toggled(bool)), this, SLOT(sortModeName(bool)) );
296   connect(radio_sort_size, SIGNAL(toggled(bool)), this, SLOT(sortModeSize(bool)) );
297   connect(radio_sort_type, SIGNAL(toggled(bool)), this, SLOT(sortModeType(bool)) );
298   connect(radio_sort_datemod, SIGNAL(toggled(bool)), this, SLOT(sortModeDateM(bool)) );
299   connect(radio_sort_datecre, SIGNAL(toggled(bool)), this, SLOT(sortModeDateC(bool)) );
300 
301 
302   //Special Keyboard Shortcuts
303   connect(nextTabLShort, SIGNAL(activated()), this, SLOT( prevTab() ) );
304   connect(nextTabRShort, SIGNAL(activated()), this, SLOT( nextTab() ) );
305   connect(togglehiddenfilesShort, SIGNAL(activated()), this, SLOT( togglehiddenfiles() ) );
306   connect(focusDirWidgetShort, SIGNAL(activated()), this, SLOT( focusDirWidget() ) );
307   //connect(toggledirtreepaneShort, SIGNAL(activated()), this, SLOT( toggleDirTreePane() ) );
308 
309 }
310 
focusDirWidget()311 void MainUI::focusDirWidget()
312 {
313   DirWidget *dir = FindActiveBrowser();
314   if(dir != 0) { dir->setFocusLineDir(); }
315 }
316 
togglehiddenfiles()317 void MainUI::togglehiddenfiles()
318 {
319     //change setChecked to inverse value
320     ui->actionView_Hidden_Files->setChecked( !settings->value("showhidden", true).toBool() );
321     // then trigger function
322     on_actionView_Hidden_Files_triggered();
323 }
324 
325 /*void MainUI::toggleDirTreePane()
326 {
327     //change setChecked to inverse value
328     ui->actionView_Hidden_Files->setChecked( !settings->value("showdirtree", true).toBool() );
329     // then trigger function
330     on_actionView_showDirTreePane_triggered();
331 }*/
332 
loadSettings()333 void MainUI::loadSettings(){
334   //Note: make sure this is run after all the UI elements are created and connected to slots
335   // but before the first directory gets loaded
336   ui->actionView_Hidden_Files->setChecked( settings->value("showhidden", false).toBool() );
337     on_actionView_Hidden_Files_triggered(); //make sure to update the models too
338   ui->actionShow_Thumbnails->setChecked( settings->value("showthumbnails",true).toBool());
339     on_actionShow_Thumbnails_triggered(); //make sure to update models too
340     //ui->actionView_showDirTreePane->setChecked( settings->value("showdirtree", false).toBool());
341     //on_actionView_showDirTreePane_triggered(); //make sure to update the models too
342   ui->actionVerify_File_Delete->setChecked( settings->value("showdeleteprompt", true).toBool());
343   //ui->actionShow_Action_Buttons->setChecked(settings->value("showactions", true).toBool() );
344     //on_actionShow_Action_Buttons_triggered(); //make sure to update the UI
345   //ui->actionShow_Thumbnails->setChecked( settings->value("showthumbnails", true).toBool() );
346   //View Type
347   //qDebug() << "View Mode:" << settings->value("viewmode","details").toString();
348   bool showDetails = (settings->value("viewmode","details").toString()=="details");
349   if(showDetails){ radio_view_details->setChecked(true); }
350   else{ radio_view_list->setChecked(true); }
351   //Grouping type
352   //bool usetabs = (settings->value("groupmode","tabs").toString()=="tabs");
353   //if(usetabs){ radio_view_tabs->setChecked(true); }
354  // else{ radio_view_cols->setChecked(true); }
355   //Sort Mode
356   int sortMode = (settings->value("sortmode","num").toInt() );
357   switch(sortMode){
358     case 0: // Name
359     radio_sort_name->setChecked(true); break;
360     case 1: // Size
361     radio_sort_size->setChecked(true); break;
362     case 2: // Type
363     radio_sort_type->setChecked(true); break;
364     case 3: // Date Modified
365     radio_sort_datemod->setChecked(true); break;
366     case 4: // Date Created
367     radio_sort_datecre->setChecked(true); break;
368 
369   } // end sortMode Switch
370 }
371 
RebuildBookmarksMenu()372 void MainUI::RebuildBookmarksMenu(){
373   //Create the bookmarks menu
374   QStringList BM = settings->value("bookmarks", QStringList()).toStringList();
375   ui->menuBookmarks->clear();
376     ui->menuBookmarks->addAction(ui->actionManage_Bookmarks);
377     ui->menuBookmarks->addAction(ui->actionAdd_Bookmark);
378     ui->menuBookmarks->addSeparator();
379   bool changed = false;
380   BM.sort(); //Sort alphabetically
381   for(int i=0; i<BM.length(); i++){
382     //NOTE 9/28/16: Don't do existance checks here - if a network drive is specified it can cause the loading process to hang significantly
383     //if(QFile::exists(BM[i].section("::::",1,1)) ){
384       QAction *act = new QAction(BM[i].section("::::",0,0),this);
385         act->setWhatsThis(BM[i].section("::::",1,1));
386       ui->menuBookmarks->addAction(act);
387     /*}else{
388       //Invalid directory - remove the bookmark
389       BM.removeAt(i);
390       i--;
391       changed = true;
392     }*/
393   }
394   if(changed){ settings->setValue("bookmarks",BM); }
395   ui->actionManage_Bookmarks->setEnabled(BM.length()>0);
396 }
397 
RebuildDeviceMenu()398 void MainUI::RebuildDeviceMenu(){
399   //Create the External Devices Menu appropriately
400   ui->menuExternal_Devices->clear();
401     ui->menuExternal_Devices->addAction( ui->actionScan );
402     ui->menuExternal_Devices->addSeparator();
403   //Scan for externally mounted devices
404   QStringList devs = LOS::ExternalDevicePaths();
405     //Output Format: <type>::::<filesystem>::::<path>  (6/24/14 - version 0.4.0 )
406         // <type> = [USB, HDRIVE, SDCARD, DVD, LVM, UNKNOWN]
407   //qDebug() << "Externally-mounted devices:" << devs;
408   //Now add them to the menu appropriately
409   for(int i=0; i<devs.length(); i++){
410     //Skip hidden mount points (usually only for system usage - not user browsing)
411     QString label, path, fs;
412       //Format inputs as necesary
413       path = devs[i].section("::::",2,2);
414       fs = devs[i].section("::::",1,1);
415       if(path.endsWith("/") && path.length()>1 ){ path.chop(1); }
416       if(path == "/"){ label = tr("Root"); }
417       else{ label = path.section("/",-1).simplified(); }
418     if(label.startsWith(".") ){ continue; }  //don't show hidden mountpoint (not usually user-browsable)
419     if(label.endsWith(".desktop")){ label = label.section(".desktop",0,-2); } //chop the shortcut suffix off the end
420     //Create entry for this device
421     if( !fs.simplified().isEmpty()){
422       //Add filesystem type to the label
423       label = QString(tr("%1 (Type: %2)")).arg(label, fs);
424     }
425     QAction *act = new QAction(label,this);
426         act->setWhatsThis(path); //full path to mountpoint
427     act->setToolTip( QString(tr("Filesystem: %1")).arg( devs[i].section("::::",1,1) ) );
428     //Now set the appropriate icon
429     QString type = devs[i].section("::::",0,0);
430     if(type=="USB"){ type = "drive-removable-media-usb"; }
431     else if(type=="HDRIVE" || type=="LVM"){ type = "drive-harddisk"; }
432     else if(type=="SDCARD"){ type = "media-flash-sd-mmc"; }
433     else if(type=="DVD"){ type = "media-optical"; }
434     else{ type = "drive-removable-media"; }
435     act->setIcon( LXDG::findIcon(type, "") );
436       ui->menuExternal_Devices->addAction(act);
437   }
438 }
439 
FindActiveBrowser()440 DirWidget* MainUI::FindActiveBrowser(){
441   //Find the current directory
442   DirWidget *curB = 0;
443   //Get the current tab ID to start with
444   QString cur = tabBar->tabWhatsThis(tabBar->currentIndex());
445   //if(cur.startsWith("#")){ cur.clear(); } //multimedia/player tab open
446 
447   if(DWLIST.length()==1){
448     //Only 1 browser open - use it
449     curB = DWLIST[0];
450   }else if(cur.startsWith("DW-")){
451     //This is a tab for a browser - just find the matching widget
452     for(int i=0; i<DWLIST.length(); i++){
453       if(DWLIST[i]->id()==cur){ curB = DWLIST[i]; break; }
454     }
455   }else{
456     //This is a bit more complex - either showing multiple columns or a non-browser tab is active
457     if(cur=="browser"){
458       //Column View
459       QWidget *focus = QApplication::focusWidget(); //the widget which currently has focus
460       for(int i=0; i<DWLIST.length(); i++){
461         if(DWLIST[i]->isAncestorOf(focus)){ curB = DWLIST[i]; break; } //This browser has focus
462       }
463     }else{
464       //Non-Browser in focus - use the fallback below
465     }
466   }
467   //if all else fails - just use the first browser in the list (there should always be at least one)
468   if(curB==0 && !DWLIST.isEmpty()){ curB = DWLIST[0];  }
469   return curB;
470 }
471 
472 //==============
473 //    PRIVATE SLOTS
474 //==============
DisplayStatusBar(QString msg)475 void MainUI::DisplayStatusBar(QString msg){
476     //qDebug() << "message to show in the status bar:" << msg;
477     ui->statusbar->showMessage(msg);
478 }
479 
480 //---------------------
481 //Menu Actions
482 //---------------------
on_actionNew_Window_triggered()483 void MainUI::on_actionNew_Window_triggered(){
484   QProcess::startDetached("lumina-fm -new-instance");
485 }
486 
on_actionNew_Tab_triggered()487 void MainUI::on_actionNew_Tab_triggered(){
488   OpenDirs(QStringList() << QDir::homePath());
489 }
490 
on_actionSearch_triggered()491 void MainUI::on_actionSearch_triggered(){
492   DirWidget *dir = FindActiveBrowser();
493   if(dir==0){ return; }
494   QProcess::startDetached("lumina-search -dir \""+dir->currentDir()+"\"");
495 }
496 
on_actionClose_Browser_triggered()497 void MainUI::on_actionClose_Browser_triggered(){
498   tabClosed();
499 }
500 
on_actionClose_triggered()501 void MainUI::on_actionClose_triggered(){
502   if(tabBar->count() > 1){
503     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 ) ){
504       return;
505     }
506   }
507   qDebug() << "Closing Down...";
508   this->close();
509 }
510 
on_actionNew_Dir_triggered()511 void MainUI::on_actionNew_Dir_triggered()
512 {
513     DirWidget::createNewFolder(this, DWLIST.at( tabBar->currentIndex())->currentBrowser() );
514 }
515 
on_actionRefresh_triggered()516 void MainUI::on_actionRefresh_triggered(){
517   DirWidget *cur = FindActiveBrowser();
518   if(cur!=0){ cur->refresh(); }
519 }
520 
on_actionView_Hidden_Files_triggered()521 void MainUI::on_actionView_Hidden_Files_triggered(){
522   worker->showHidden = ui->actionView_Hidden_Files->isChecked();
523   //Now save this setting for later
524   settings->setValue("showhidden", ui->actionView_Hidden_Files->isChecked());
525   //worker->showHidden = ui->actionView_Hidden_Files->isChecked();
526   //Re-load the current browsers
527   for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->showHidden( ui->actionView_Hidden_Files->isChecked() ); }//DWLIST[i]->refresh(); }
528 
529 }
530 
on_actionVerify_File_Delete_triggered()531 void MainUI::on_actionVerify_File_Delete_triggered(){
532 //Now save this setting for later
533   settings->setValue("showdeleteprompt", ui->actionView_Hidden_Files->isChecked());
534 }
535 
treeWidgetWidthChanged(float percent)536 void MainUI::treeWidgetWidthChanged(float percent){
537   //NOTE: Percent needs to be between 0-75
538   if(percent > 75){ percent = 75; }
539   settings->setValue("dirTree_width", percent);
540   //Re-load the current browsers
541   for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->adjustTreeWidget(percent); }
542 }
543 
544 
on_actionShow_Thumbnails_triggered()545 void MainUI::on_actionShow_Thumbnails_triggered(){
546   //Now save this setting for later
547   bool show = ui->actionShow_Thumbnails->isChecked();
548   settings->setValue("showthumbnails", show);
549   for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->showThumbnails(show); }
550 }
551 
goToBookmark(QAction * act)552 void MainUI::goToBookmark(QAction *act){
553   if(act==ui->actionManage_Bookmarks){
554     BMMDialog dlg(this);
555       dlg.loadSettings(settings);
556       dlg.exec();
557     RebuildBookmarksMenu();
558   }else if(act == ui->actionAdd_Bookmark){
559     CreateBookMark();
560   }else{
561     //Find the current directory
562     DirWidget *dir = FindActiveBrowser();
563     if(dir!=0){
564       dir->ChangeDir(act->whatsThis());
565       return;
566     }
567     //If no current dir could be found - open a new tab/column
568     OpenDirs(QStringList() << act->whatsThis() );
569   }
570 }
571 
goToDevice(QAction * act)572 void MainUI::goToDevice(QAction *act){
573   if(act==ui->actionScan){
574     RebuildDeviceMenu();
575   }else{
576     QString action = act->whatsThis();
577     if(action.endsWith(".desktop")){
578       //Find the actual action/directory within this shortcut
579       XDGDesktop xdg(action);
580       if(xdg.type==XDGDesktop::DIR){
581         action = xdg.path; //use the new path
582       }else{
583         //Need to run the full open routine on this shortcut
584         QProcess::startDetached("lumina-open", QStringList() << action);
585         return;
586       }
587     }else if( !QFileInfo(action).isDir() ){
588         //Need to run the full open routine on this file since it is not a directory
589         QProcess::startDetached("lumina-open", QStringList() << action);
590         return;
591     }
592     DirWidget *dir = FindActiveBrowser();
593     if(dir!=0){
594       dir->ChangeDir(action);
595       return;
596     }
597     //If no current dir could be found - open a new tab/column
598     OpenDirs(QStringList() << action );
599   }
600 }
601 
viewModeChanged(bool active)602 void MainUI::viewModeChanged(bool active){
603   if(!active){ return; } //on every view change, all radio buttons will call this function - only run this once though
604   bool showDetails = radio_view_details->isChecked();
605   if(showDetails){ settings->setValue("viewmode","details"); }
606   else{ settings->setValue("viewmode","list"); }
607 
608   //Re-load the view widgets
609   for(int i=0; i<DWLIST.length(); i++){
610     DWLIST[i]->setShowDetails(showDetails);
611   }
612 ui->menuView_Mode->hide();
613 }
614 
615 
sortModeName(bool active)616 void MainUI::sortModeName(bool active){
617   if(!active){ return; }
618   bool sortbyName = radio_sort_name->isChecked();
619   settings->setValue("sortmode","0");
620   for(int i=0; i<DWLIST.length(); i++){
621     DWLIST[i]->setTreeSortMode(0);
622   }
623   ui->menuSort_Mode->hide();
624 }
625 
sortModeSize(bool active)626 void MainUI::sortModeSize(bool active){
627   if(!active){ return; }
628   bool sortbySize = radio_sort_size->isChecked();
629   settings->setValue("sortmode","1");
630   for(int i=0; i<DWLIST.length(); i++){
631     DWLIST[i]->setTreeSortMode(1);
632   }
633   ui->menuSort_Mode->hide();
634 }
635 
sortModeType(bool active)636 void MainUI::sortModeType(bool active){
637   if(!active){ return; }
638   bool sortbyType = radio_sort_type->isChecked();
639   settings->setValue("sortmode","2");
640   for(int i=0; i<DWLIST.length(); i++){
641     DWLIST[i]->setTreeSortMode(2);
642   }
643   ui->menuSort_Mode->hide();
644 }
645 
sortModeDateM(bool active)646 void MainUI::sortModeDateM(bool active){
647   if(!active){ return; }
648   bool sortbyDateM = radio_sort_datemod->isChecked();
649   settings->setValue("sortmode","3");
650   for(int i=0; i<DWLIST.length(); i++){
651     DWLIST[i]->setTreeSortMode(3);
652   }
653   ui->menuSort_Mode->hide();
654 }
655 
sortModeDateC(bool active)656 void MainUI::sortModeDateC(bool active){
657   if(!active){ return; }
658   bool sortbyDateC = radio_sort_datecre->isChecked();
659   settings->setValue("sortmode","4");
660   for(int i=0; i<DWLIST.length(); i++){
661     DWLIST[i]->setTreeSortMode(4);
662   }
663   ui->menuSort_Mode->hide();
664 }
665 
666 /*void MainUI::groupModeChanged(bool active){
667   if(!active){ return; } //on every change, all radio buttons will call this function - only run this once though
668   //bool usetabs = radio_view_tabs->isChecked();
669  //if(usetabs){
670     //settings->setValue("groupmode","tabs");
671     //Now clean up all the tabs (remove the generic one and add the specific ones)
672     for(int i=0; i<tabBar->count(); i++){
673       //Remove all the browser tabs
674       if( !tabBar->tabWhatsThis(i).startsWith("#") ){
675     tabBar->removeTab(i);
676     i--; //go back one to ensure nothing is missed
677       }
678     }
679     //Create all the specific browser tabs for open browsers
680     for(int i=0; i<DWLIST.length(); i++){
681       qDebug() << "Add specific tab:" << DWLIST[i]->currentDir() << DWLIST[i]->id();
682       int tab = tabBar->addTab( LXDG::findIcon("folder-open",""), DWLIST[i]->currentDir().section("/",-1) );
683       tabBar->setTabWhatsThis(tab, DWLIST[i]->id() );
684       //DWLIST[i]->setShowCloseButton(false);
685     }
686   }else{
687     settings->setValue("groupmode","columns");
688     //Now clean up the tabs (remove the specific ones and add a generic one)
689     for(int i=0; i<tabBar->count(); i++){
690       //Remove all the browser tabs
691       if( !tabBar->tabWhatsThis(i).startsWith("#") ){
692     tabBar->removeTab(i);
693     i--; //go back one to ensure nothing is missed
694       }
695     }
696     //Now create the generic "browser" tab
697     int tab = tabBar->addTab( LXDG::findIcon("folder-open",""), tr("Browser") );
698       tabBar->setTabWhatsThis(tab, "browser" );
699     //for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->setShowCloseButton(true); }
700   }
701   if(tabBar->currentIndex()<0){ tabBar->setCurrentIndex(0); }
702   tabBar->setVisible( tabBar->count() > 1 );
703   QTimer::singleShot(20, this, SLOT(tabChanged()) );
704 }*/
705 
on_actionLarger_Icons_triggered()706 void MainUI::on_actionLarger_Icons_triggered(){
707   int size = settings->value("iconsize", 32).toInt();
708   size += 16;
709   for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->setThumbnailSize(size); }
710   settings->setValue("iconsize", size);
711 }
712 
on_actionSmaller_Icons_triggered()713 void MainUI::on_actionSmaller_Icons_triggered(){
714   int size = settings->value("iconsize", 32).toInt();
715   if(size <= 16){ return; }
716   size -= 16;
717   for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->setThumbnailSize(size); }
718   settings->setValue("iconsize", size);
719 }
720 
CreateBookMark()721 void MainUI::CreateBookMark(){
722   QString dir = FindActiveBrowser()->currentDir();
723   bool ok = false;
724   QString name = QInputDialog::getText(this, tr("New Bookmark"), tr("Name:"), QLineEdit::Normal, dir, \
725         &ok, 0, Qt::ImhFormattedNumbersOnly | Qt::ImhUppercaseOnly | Qt::ImhLowercaseOnly);
726   if(!ok || name.isEmpty()){ return; } //cancelled
727   QStringList BM = settings->value("bookmarks",QStringList()).toStringList();
728   if(BM.filter(name+"::::").length() >0){
729     QMessageBox::warning(this, tr("Invalid Name"), tr("This bookmark name already exists. Please choose another.") );
730     QTimer::singleShot(0,this, SLOT(on_actionBookMark_triggered()));
731     return;
732   }
733   BM.append(name+"::::"+dir);
734   BM.sort(); //sort alphabetically by name
735   settings->setValue("bookmarks", BM);
736   //Now rebuild the bookmarks menu
737   RebuildBookmarksMenu();
738 }
739 
740 //Git Menu options
on_menuGit_aboutToShow()741 void MainUI::on_menuGit_aboutToShow(){
742   QString dir = FindActiveBrowser()->currentDir();
743   bool inrepo = GIT::isRepo(dir);
744   ui->actionRepo_Status->setEnabled( inrepo );
745   ui->actionClone_Repository->setEnabled( !inrepo );
746 }
747 
on_actionRepo_Status_triggered()748 void MainUI::on_actionRepo_Status_triggered(){
749   QString status = GIT::status( FindActiveBrowser()->currentDir() );
750   QMessageBox::information(this, tr("Git Repository Status"), status);
751 }
752 
on_actionClone_Repository_triggered()753 void MainUI::on_actionClone_Repository_triggered(){
754   GitWizard *dlg = new GitWizard(this);
755     dlg->setWorkingDir( FindActiveBrowser()->currentDir() );
756   dlg->show();
757 }
758 
759 
tabChanged(int tab)760 void MainUI::tabChanged(int tab){
761   if(tab<0){ tab = tabBar->currentIndex(); }
762   if(tab < 0){ return; }
763   //Load the directory contained in the new tab
764   QString info = tabBar->tabWhatsThis(tab); //get the full directory
765   if(info.isEmpty()){ return; } //unknown tab (this happens while we are in the middle of making changes to tabs - just ignore it)
766   //qDebug() << "Change to Tab:" << tab << tabBar->tabText(tab);
767   //qDebug() << " -- ID:" << info;
768   if(info=="#MW"){ ui->stackedWidget->setCurrentWidget(ui->page_player); }
769   else if(info=="#SW"){ ui->stackedWidget->setCurrentWidget(ui->page_image); }
770   else{
771     ui->stackedWidget->setCurrentWidget(ui->page_browser);
772     //if(radio_view_tabs->isChecked()){
773       for(int i=0; i<DWLIST.length(); i++){
774      DWLIST[i]->setVisible(DWLIST[i]->id()==info);
775       }
776     /*}else{
777       //For columns, all widgets need to be visible
778       for(int i=0; i<DWLIST.length(); i++){
779      DWLIST[i]->setVisible(true);
780       }
781     }*/
782   }
783   tabBar->setVisible( tabBar->count() > 1 );
784 }
785 
tabClosed(int tab)786 void MainUI::tabClosed(int tab){
787   if(tabBar->count()==1){ return; } //Can't close the only tab
788   if(tab < 0){ tab = tabBar->currentIndex(); }
789   QString info = tabBar->tabWhatsThis(tab);
790   if(info=="browser"){ return; }
791   //qDebug() << "Tab Closed:" << info;
792    if(!info.startsWith("#")){
793     for(int i=0; i<DWLIST.length(); i++){
794       if(info == DWLIST[i]->id()){
795      DWLIST[i]->cleanup();
796         delete DWLIST.takeAt(i);
797     break;
798       }
799     }
800    }else if(info=="#MW"){
801       MW->Cleanup(); //prepare it to be hidden/removed
802    }
803   //Remove the tab (will automatically move to a different one);
804   qDebug() << "Closing tab:" << tab << tabBar->tabText(tab);
805   tabBar->removeTab(tab);
806   tabBar->setVisible( tabBar->count() > 1 );
807   if(DWLIST.isEmpty()){ OpenDirs(QStringList() << QDir::homePath() ); }
808 }
809 
prevTab()810 void MainUI::prevTab(){
811   int cur = tabBar->currentIndex();
812   if(cur == 0){ tabBar->setCurrentIndex( tabBar->count()-1 ); }
813   else{ tabBar->setCurrentIndex( cur-1 ); }
814 }
815 
nextTab()816 void MainUI::nextTab(){
817   int cur = tabBar->currentIndex();
818   if(cur == (tabBar->count()-1) ){ tabBar->setCurrentIndex(0); }
819   else{ tabBar->setCurrentIndex( cur+1 ); }
820 }
821 
822 
SnapshotDataAvailable(QString id,QString dir,QStringList list)823 void MainUI::SnapshotDataAvailable(QString id , QString dir, QStringList list){
824   for(int i=0; i<DWLIST.length(); i++){
825     if(id == DWLIST[i]->id()){
826       DWLIST[i]->LoadSnaps(dir, list);
827       break;
828     }
829   }
830 }
831 
OpenPlayer(LFileInfoList list)832 void MainUI::OpenPlayer(LFileInfoList list){
833   //See if the tab is available for the multimedia player
834   int tab = -1;
835   for(int i=0; i<tabBar->count(); i++){
836     if(tabBar->tabWhatsThis(i)=="#MW"){ tab=i; break;}
837   }
838   if(tab<0){
839     //Need to create a new tab
840     tab = tabBar->addTab(LXDG::findIcon("media-playback-start",""), tr("Multimedia"));
841     tabBar->setTabWhatsThis(tab,"#MW");
842     //Also clear the info in the player
843     MW->ClearPlaylist();
844   }
845   //Load the data into the player
846   MW->LoadMultimedia(list);
847   //Switch to the player tab
848   tabBar->setCurrentIndex(tab);
849 }
850 
OpenImages(LFileInfoList list)851 void MainUI::OpenImages(LFileInfoList list){
852   int tab = -1;
853   for(int i=0; i<tabBar->count(); i++){
854     if(tabBar->tabWhatsThis(i)=="#SW"){ tab=i; break;}
855   }
856   if(tab<0){
857     //Need to create a new tab
858     tab = tabBar->addTab(LXDG::findIcon("media-slideshow",""), tr("Slideshow"));
859     tabBar->setTabWhatsThis(tab,"#SW");
860     //Also clear the info in the viewer
861     SW->ClearImages();
862   }
863   //Load the data into the viewer
864   SW->LoadImages(list);
865   //Switch to the player tab
866   tabBar->setCurrentIndex(tab);
867   QTimer::singleShot(20, SW, SLOT(refresh()) );
868 }
869 
OpenTerminal(QString dirpath)870 void MainUI::OpenTerminal(QString dirpath){
871   //we use the application defined as the default terminal
872   //QSettings sessionsettings( QSettings::UserScope, "LuminaDE","sessionsettings", this);
873   //xterm remains the default
874   QString defTerminal = LXDG::findDefaultAppForMime("application/terminal"); //sessionsettings.value("default-terminal", "xterm").toString();
875   qDebug() << "Found default terminal:" << defTerminal;
876   //Now get the exec string and run it
877   QString cmd = LUtils::GenerateOpenTerminalExec(defTerminal, dirpath);
878   //qDebug() << "Starting Terminal with command:" << cmd;
879   QProcess::startDetached(cmd);
880 
881 }
882 
CutFiles(QStringList list)883 void MainUI::CutFiles(QStringList list){
884   qDebug() << "Cut Files:" << list;
885   if(list.isEmpty()){ return; } //nothing selected
886   //Format the data string
887   QList<QUrl> urilist; //Also assemble a URI list for cros-app compat (no copy/cut distinguishing)
888   for(int i=0; i<list.length(); i++){
889     urilist << QUrl::fromLocalFile(list[i]);
890     list[i] = list[i].prepend("cut::::");
891   }
892   //Now save that data to the global clipboard
893   QMimeData *dat = new QMimeData;
894     dat->clear();
895     dat->setData("x-special/lumina-copied-files", list.join("\n").toLocal8Bit());
896     dat->setUrls(urilist); //the text/uri-list mimetype - built in Qt conversion/use
897   QApplication::clipboard()->clear();
898   QApplication::clipboard()->setMimeData(dat);
899   //Update all the buttons to account for clipboard change
900   //for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->refreshButtons(); }
901 }
902 
CopyFiles(QStringList list)903 void MainUI::CopyFiles(QStringList list){
904   qDebug() << "Copy Files:" << list;
905   if(list.isEmpty()){ return; } //nothing selected
906   //Format the data string
907   QList<QUrl> urilist; //Also assemble a URI list for cros-app compat (no copy/cut distinguishing)
908   for(int i=0; i<list.length(); i++){
909     urilist << QUrl::fromLocalFile(list[i]);
910     list[i] = list[i].prepend("copy::::");
911   }
912   //Now save that data to the global clipboard
913   QMimeData *dat = new QMimeData;
914     dat->clear();
915     dat->setData("x-special/lumina-copied-files", list.join("\n").toLocal8Bit());
916     dat->setUrls(urilist); //the text/uri-list mimetype - built in Qt conversion/use
917   QApplication::clipboard()->clear();
918   QApplication::clipboard()->setMimeData(dat);
919   //Update all the buttons to account for clipboard change
920   //for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->refreshButtons(); }
921 }
922 
PasteFiles(QString dir,QStringList raw)923 void MainUI::PasteFiles(QString dir, QStringList raw){
924   qDebug() << "Paste Files:" << dir;
925   QStringList cut, copy, newcut, newcopy;
926   if(raw.isEmpty()){
927     //Pull info from the clipboard
928     const QMimeData *dat = QApplication::clipboard()->mimeData();
929     raw = QString(dat->data("x-special/lumina-copied-files")).split("\n");
930   }
931   if(!dir.endsWith("/")){ dir.append("/"); }
932   for(int i=0; i<raw.length(); i++){
933     if(raw[i].startsWith("cut::::")){
934     cut << raw[i].section("::::",1,50);
935     newcut << dir+raw[i].section("::::",1,50).section("/",-1);
936     }
937     else if(raw[i].startsWith("copy::::")){
938     copy << raw[i].section("::::",1,50);
939     newcopy<< dir+raw[i].section("::::",1,50).section("/",-1);
940     }
941   }
942   //bool errs = false;
943   //Perform the copy/move operations
944   //worker->pauseData = true; //pause any info requests
945   if(!copy.isEmpty()){
946     qDebug() << "Paste Copy:" << copy << "->" << newcopy;
947     TRAY->StartOperation( TrayUI::COPY, copy, newcopy);
948     /*FODialog dlg(this);
949       if( !dlg.CopyFiles(copy, newcopy) ){ return; } //cancelled
950       dlg.show();
951       dlg.exec();
952       errs = errs || !dlg.noerrors;*/
953   }
954   if(!cut.isEmpty()){
955     qDebug() << "Paste Cut:" << cut << "->" << newcut;
956     TRAY->StartOperation(TrayUI::MOVE, cut, newcut);
957     /*FODialog dlg(this);
958       if(!dlg.MoveFiles(cut, newcut) ){ return; } //cancelled
959       dlg.show();
960       dlg.exec();
961       errs = errs || !dlg.noerrors;*/
962   }
963   //worker->pauseData = false; //resume info requests
964   //Modify the clipboard appropriately
965   if(!cut.isEmpty()){
966     //Now clear the clipboard since those old file locations are now invalid
967     QApplication::clipboard()->clear();
968     if(!copy.isEmpty()){
969       //There were also files copied: save those files back into the clipboard
970        QMimeData *dat = new QMimeData;
971     dat->clear();
972     dat->setData("x-special/lumina-copied-files", raw.filter("copy::::").join("\n").toLocal8Bit());
973     QApplication::clipboard()->setMimeData(dat);
974     }
975   }
976   //Update all the buttons to account for clipboard change
977   //for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->refresh(); }
978 }
979 
FavoriteFiles(QStringList list)980 void MainUI::FavoriteFiles(QStringList list){
981   qDebug() << "Favorite Files:" << list;
982   for(int i=0; i<list.length(); i++){
983     LDesktopUtils::addFavorite(list[i]);
984   }
985   //Might want to make this a "toggle" instead of an add later on...
986 }
987 
RenameFiles(QStringList list)988 void MainUI::RenameFiles(QStringList list){
989   qDebug() << "Rename Files:" << list;
990   for(int i=0; i<list.length(); i++){
991     QString fname = list[i];
992     QString path = fname;
993     fname = fname.section("/",-1); //turn this into just the file name
994     path.chop(fname.length()); 	//turn this into the base directory path (has a "/" at the end)
995     //Now prompt for the new filename
996     bool ok = false;
997     QString nname = QInputDialog::getText(this, tr("Rename File"),tr("New Name:"), QLineEdit::Normal, fname, &ok);
998     if(!ok || nname.isEmpty()){ return; } //cancelled
999     //Now check for a file extension and add it if necessary
1000     QString oext = fname.section(".",-1);
1001       if("."+oext == fname){ oext.clear(); } //hidden file without an extension
1002       else if(oext==fname){ oext.clear(); } //no extension
1003     QString next = nname.section(".",-1);
1004       if(next==nname){ next.clear(); } //no extension
1005     if(next.isEmpty() && !oext.isEmpty()){
1006       nname.append( "."+oext );
1007     }
1008     //Check if this filename already exists
1009     bool overwrite = QFile::exists(path+nname);
1010     if(overwrite){
1011       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) ){
1012         return; //cancelled
1013       }
1014     }
1015     //Now perform the move
1016     //Don't pause the background worker for a simple rename - this operation is extremely fast
1017     qDebug() << "Rename:" << path+fname << "->" << path+nname;
1018     TRAY->StartOperation(TrayUI::MOVE, QStringList() << path+fname, QStringList() << path+nname);
1019     /*FODialog dlg(this);
1020       dlg.setOverwrite(overwrite);
1021       dlg.MoveFiles(QStringList() << path+fname, QStringList() << path+nname);
1022       dlg.show();
1023       dlg.exec();*/
1024   } //end loop over list of files
1025 }
1026 
RemoveFiles(QStringList list)1027 void MainUI::RemoveFiles(QStringList list){
1028   if(list.isEmpty()){ return; } //nothing selected
1029   qDebug() << "Remove Files:" << list;
1030   QStringList paths, names;
1031   for(int i=0; i<list.length(); i++){
1032      paths << list[i];
1033      names << list[i].section("/",-1);
1034    }
1035 
1036   //Verify permanent removal of file/dir
1037   if(ui->actionVerify_File_Delete->isChecked()){
1038     QMessageBox dlgQ(QMessageBox::Question, tr("Verify Removal"), tr("WARNING: This will permanently delete the file(s) from the system!")+"\n"+tr("Are you sure you want to continue?"), QMessageBox::Yes | QMessageBox::No, this);
1039       dlgQ.setDetailedText(tr("Items to be removed:")+"\n\n"+names.join("\n"));
1040     dlgQ.exec();
1041     if(dlgQ.result() != QMessageBox::Yes){ return; } //cancelled
1042   }
1043 
1044   //Now remove the file/dir
1045   qDebug() << " - Delete: "<<paths;
1046   TRAY->StartOperation(TrayUI::DELETE, paths, QStringList());
1047   //worker->pauseData = true; //pause any info requests
1048   /*FODialog dlg(this);
1049     dlg.RemoveFiles(paths);
1050     dlg.show();
1051     dlg.exec();*/
1052   //worker->pauseData = false; //resume info requests
1053   //for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->refresh(); }
1054 }
1055 
CloseBrowser(QString ID)1056 void MainUI::CloseBrowser(QString ID){
1057   //Find the tab associated with this browser first
1058   for(int i=0; i<tabBar->count(); i++){
1059     if(tabBar->tabWhatsThis(i)==ID){
1060       tabBar->removeTab(i);
1061       break;
1062     }
1063   }
1064   //Now remove the browser itself
1065   for(int i=0; i<DWLIST.length(); i++){
1066     if(DWLIST[i]->id()==ID){
1067       delete DWLIST.takeAt(i);
1068       break;
1069     }
1070   }
1071   //If the last browser was just closed, create a new one
1072   if(DWLIST.isEmpty()){
1073     OpenDirs(QStringList() << QDir::homePath());
1074   }
1075 }
1076 
TabNameChanged(QString id,QString name)1077 void MainUI::TabNameChanged(QString id, QString name){
1078   for(int i=0; i<tabBar->count(); i++){
1079     if(tabBar->tabWhatsThis(i)==id){
1080       tabBar->setTabText(i, name);
1081       return;
1082     }
1083   }
1084 }
1085 
TrayJobsFinished()1086 void MainUI::TrayJobsFinished(){
1087   if(waitingToClose){ this->close(); }
1088 }
1089 
1090 //=============
1091 //  PROTECTED
1092 //=============
closeEvent(QCloseEvent * ev)1093 void MainUI::closeEvent(QCloseEvent *ev){
1094   //See if the tray is active or not first
1095   if(TRAY!=0){
1096     if(TRAY->isVisible() && !waitingToClose){
1097       this->hide();
1098       ev->ignore();
1099       waitingToClose = true;
1100       return;
1101     }
1102   }
1103   QMainWindow::closeEvent(ev); //continue normal close routine
1104 }
1105 
on_actionOpen_as_Root_triggered()1106 void MainUI::on_actionOpen_as_Root_triggered()
1107 {
1108     ExternalProcess::launch("qsudo lumina-fm");
1109 }
1110