diff options
Diffstat (limited to 'src-qt5/desktop-utils/lumina-fm/widgets')
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/widgets/DDListWidgets.h | 125 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.cpp | 1049 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.h | 229 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.ui | 527 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.cpp | 734 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.h | 173 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.ui | 249 |
7 files changed, 1263 insertions, 1823 deletions
diff --git a/src-qt5/desktop-utils/lumina-fm/widgets/DDListWidgets.h b/src-qt5/desktop-utils/lumina-fm/widgets/DDListWidgets.h index e3de9b0e..254362fd 100644 --- a/src-qt5/desktop-utils/lumina-fm/widgets/DDListWidgets.h +++ b/src-qt5/desktop-utils/lumina-fm/widgets/DDListWidgets.h @@ -24,6 +24,8 @@ #include <QUrl> #include <QDir> +#include <LUtils.h> + //============== // LIST WIDGET //============== @@ -42,22 +44,30 @@ public: this->setFlow(QListView::TopToBottom); this->setWrapping(true); this->setMouseTracking(true); - //this->setSortingEnabled(true); //This sorts *only* by name - type is not preserved + this->setSortingEnabled(true); //This sorts *only* by name - type is not preserved + //this->setStyleSheet("QListWidget::item{ border: 1px solid transparent; border-radius: 5px; background-color: transparent;} QListWidget::item:hover{ border-color: black; } QListWidget::item:focus{ border-color: lightblue; }"); } ~DDListWidget(){} signals: void DataDropped(QString, QStringList); //Dir path, List of commands - + void GotFocus(); + protected: + void focusInEvent(QFocusEvent *ev){ + QListWidget::focusInEvent(ev); + emit GotFocus(); + } + void startDrag(Qt::DropActions act){ QList<QListWidgetItem*> items = this->selectedItems(); if(items.length()<1){ return; } QList<QUrl> urilist; for(int i=0; i<items.length(); i++){ - urilist << QUrl::fromLocalFile(items[i]->whatsThis().section("::::",1,100)); + urilist << QUrl::fromLocalFile(items[i]->whatsThis()); } //Create the mime data + //qDebug() << "Start Drag:" << urilist; QMimeData *mime = new QMimeData; mime->setUrls(urilist); //Create the drag structure @@ -76,19 +86,23 @@ protected: ev->acceptProposedAction(); //allow this to be dropped here }else{ ev->ignore(); - } + } } void dragMoveEvent(QDragMoveEvent *ev){ if(ev->mimeData()->hasUrls() && !this->whatsThis().isEmpty() ){ //Change the drop type depending on the data/dir QString home = QDir::homePath(); - if( this->whatsThis().startsWith(home) ){ ev->setDropAction(Qt::MoveAction); } - else{ ev->setDropAction(Qt::CopyAction); } + //qDebug() << "Drag Move:" << home << this->whatsThis(); + if( this->whatsThis().startsWith(home) ){ ev->setDropAction(Qt::MoveAction); this->setCursor(Qt::DragMoveCursor); } + else{ ev->setDropAction(Qt::CopyAction); this->setCursor(Qt::DragCopyCursor);} ev->acceptProposedAction(); //allow this to be dropped here + //this->setCursor(Qt::CrossCursor); }else{ + this->setCursor(Qt::ForbiddenCursor); ev->ignore(); } + this->update(); } void dropEvent(QDropEvent *ev){ @@ -99,7 +113,8 @@ protected: //See if the item under the drop point is a directory or not QListWidgetItem *it = this->itemAt( ev->pos()); if(it!=0){ - QFileInfo info(it->whatsThis().section("::::",1,100)); + //qDebug() << "Drop Item:" << it->whatsThis(); + QFileInfo info(it->whatsThis()); if(info.isDir() && info.isWritable()){ dirpath = info.absoluteFilePath(); } @@ -110,11 +125,13 @@ protected: foreach(const QUrl &url, ev->mimeData()->urls()){ const QString filepath = url.toLocalFile(); //If the target file is modifiable, assume a move - otherwise copy - if(QFileInfo(filepath).isWritable() && (filepath.startsWith(home) && dirpath.startsWith(home))){ files << "cut::::"+filepath; } - else{ files << "copy::::"+filepath; } + if(QFileInfo(filepath).isWritable() && (filepath.startsWith(home) && dirpath.startsWith(home))){ + if(filepath.section("/",0,-2)!=dirpath){ files << "cut::::"+filepath; } //don't "cut" a file into the same dir + }else{ files << "copy::::"+filepath; } } - //qDebug() << "Drop Event:" << dirpath; - emit DataDropped( dirpath, files ); + //qDebug() << "Drop Event:" << dirpath << files; + if(!files.isEmpty()){ emit DataDropped( dirpath, files ); } + this->setCursor(Qt::ArrowCursor); } void mouseReleaseEvent(QMouseEvent *ev){ @@ -155,14 +172,19 @@ public: signals: void DataDropped(QString, QStringList); //Dir path, List of commands - + void GotFocus(); + protected: + void focusInEvent(QFocusEvent *ev){ + QTreeWidget::focusInEvent(ev); + emit GotFocus(); + } void startDrag(Qt::DropActions act){ QList<QTreeWidgetItem*> items = this->selectedItems(); if(items.length()<1){ return; } QList<QUrl> urilist; for(int i=0; i<items.length(); i++){ - urilist << QUrl::fromLocalFile(items[i]->whatsThis(0).section("::::",1,100)); + urilist << QUrl::fromLocalFile(items[i]->whatsThis(0)); } //Create the mime data QMimeData *mime = new QMimeData; @@ -205,7 +227,7 @@ protected: //See if the item under the drop point is a directory or not QTreeWidgetItem *it = this->itemAt( ev->pos()); if(it!=0){ - QFileInfo info(it->whatsThis(0).section("::::",1,100)); + QFileInfo info(it->whatsThis(0)); if(info.isDir() && info.isWritable()){ dirpath = info.absoluteFilePath(); } @@ -216,9 +238,10 @@ protected: QString home = QDir::homePath(); foreach(const QUrl &url, ev->mimeData()->urls()){ const QString filepath = url.toLocalFile(); - //If the target file is modifiable, assume a move - otherwise copy - if(QFileInfo(filepath).isWritable() && (filepath.startsWith(home) && dirpath.startsWith(home)) ){ files << "cut::::"+filepath; } - else{ files << "copy::::"+filepath; } + //If the target file is modifiable, assume a move - otherwise copy + if(QFileInfo(filepath).isWritable() && (filepath.startsWith(home) && dirpath.startsWith(home))){ + if(filepath.section("/",0,-2)!=dirpath){ files << "cut::::"+filepath; } //don't "cut" a file into the same dir + }else{ files << "copy::::"+filepath; } } //qDebug() << "Drop Event:" << dirpath; emit DataDropped( dirpath, files ); @@ -237,4 +260,70 @@ protected: else{ QTreeWidget::mouseMoveEvent(ev); } //pass it along to the widget }*/ }; -#endif
\ No newline at end of file + +/* + * Virtual class for managing the sort of folders/files items. The problem with base class is that it only manages texts fields and + * we have dates and sizes. + * + * On this class, we overwrite the function operator<. + */ + +class CQTreeWidgetItem : public QTreeWidgetItem { +public: + CQTreeWidgetItem(int type = Type) : QTreeWidgetItem(type) {} + CQTreeWidgetItem(const QStringList & strings, int type = Type) : QTreeWidgetItem(strings, type) {} + CQTreeWidgetItem(QTreeWidget * parent, int type = Type) : QTreeWidgetItem(parent, type) {} + CQTreeWidgetItem(QTreeWidget * parent, const QStringList & strings, int type = Type) : QTreeWidgetItem(parent, strings, type) {} + CQTreeWidgetItem(QTreeWidget * parent, QTreeWidgetItem * preceding, int type = Type) : QTreeWidgetItem(parent, preceding, type) {} + CQTreeWidgetItem(QTreeWidgetItem * parent, int type = Type) : QTreeWidgetItem(parent, type) {} + CQTreeWidgetItem(QTreeWidgetItem * parent, const QStringList & strings, int type = Type) : QTreeWidgetItem(parent, strings, type) {} + CQTreeWidgetItem(QTreeWidgetItem * parent, QTreeWidgetItem * preceding, int type = Type) : QTreeWidgetItem(parent, preceding, type) {} + virtual ~CQTreeWidgetItem() {} + inline virtual bool operator<(const QTreeWidgetItem &tmp) const { + int column = this->treeWidget()->sortColumn(); + // We are in date text + if(column == 3 || column == 4){ + return this->whatsThis(column) < tmp.whatsThis(column); + // We are in size text + }else if(column == 1) { + QString text = this->text(column); + QString text_tmp = tmp.text(column); + double filesize, filesize_tmp; + // On folders, text is empty so we check for that + // In case we are in folders, we put -1 for differentiate of regular files with 0 bytes. + // Doing so, all folders we'll be together instead of mixing with files with 0 bytes. + if(text.isEmpty()) + filesize = -1; + else + filesize = LUtils::DisplaySizeToBytes(text); + if(text_tmp.isEmpty()) + filesize_tmp = -1; + else + filesize_tmp = LUtils::DisplaySizeToBytes(text_tmp); + return filesize < filesize_tmp; + + //Name column - still sort by type too (folders first) + }else if(column == 0 && (this->text(2).isEmpty() || tmp.text(2).isEmpty()) ){ + if(this->text(2) != tmp.text(2)){ return this->text(2).isEmpty(); } + } + // In other cases, we trust base class implementation + return QTreeWidgetItem::operator<(tmp); + } +}; + +//Item override for sorting purposes of list widget items +class CQListWidgetItem : public QListWidgetItem { +public: + CQListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = Q_NULLPTR) : QListWidgetItem(icon,text,parent) {} + virtual ~CQListWidgetItem() {} + inline virtual bool operator<(const QListWidgetItem &tmp) const { + QString type = this->data(Qt::UserRole).toString(); + QString tmptype = tmp.data(Qt::UserRole).toString(); + //Sort by type first + if(type!=tmptype){ return (QString::compare(type,tmptype)<0); } + //Then sort by name using the normal rules + return QListWidgetItem::operator<(tmp); + } +}; + +#endif diff --git a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.cpp b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.cpp deleted file mode 100644 index a23c9aec..00000000 --- a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.cpp +++ /dev/null @@ -1,1049 +0,0 @@ -//=========================================== -// Lumina-DE source code -// Copyright (c) 2015, Ken Moore -// Available under the 3-clause BSD license -// See the LICENSE file for full details -//=========================================== -#include "DirWidget.h" -#include "ui_DirWidget.h" - -#include <QMessageBox> -#include <QCursor> -#include <QClipboard> -#include <QMimeData> -#include <QTimer> -#include <QInputDialog> -#include <QScrollBar> -#include <QSettings> -#include <QtConcurrent/QtConcurrentRun> - -#include <LuminaOS.h> -#include <LuminaXDG.h> -#include <LuminaUtils.h> - -#include "../ScrollDialog.h" - -#define DEBUG 0 - - -const QString sessionsettings_config_file = QDir::homePath() + "/.lumina/LuminaDE/sessionsettings.conf"; - -DirWidget::DirWidget(QString objID, QWidget *parent) : QWidget(parent), ui(new Ui::DirWidget){ - ui->setupUi(this); //load the designer file - ID = objID; - //Assemble the toolbar for the widget - toolbar = new QToolBar(this); - toolbar->setContextMenuPolicy(Qt::CustomContextMenu); - toolbar->setFloatable(false); - toolbar->setMovable(false); - toolbar->setOrientation(Qt::Horizontal); - toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly); - //toolbar->setIconSize(QSize(32,32)); - ui->toolbar_layout->addWidget(toolbar); - // - Add the buttons to the toolbar - toolbar->addAction(ui->actionBack); - toolbar->addAction(ui->actionUp); - toolbar->addAction(ui->actionHome); - line_dir = new QLineEdit(this); - toolbar->addWidget(line_dir); - toolbar->addAction(ui->actionStopLoad); - toolbar->addAction(ui->actionClose_Browser); - //Add the browser widgets - listWidget = new DDListWidget(this); - treeWidget = new DDTreeWidget(this); - ui->browser_layout->addWidget(listWidget); - ui->browser_layout->addWidget(treeWidget); - //Create the keyboard shortcuts - /*copyFilesShort = new QShortcut( QKeySequence(tr("Ctrl+C")), this); - pasteFilesShort = new QShortcut( QKeySequence(tr("Ctrl+V")), this); - cutFilesShort = new QShortcut( QKeySequence(tr("Ctrl+X")), this); - deleteFilesShort = new QShortcut( QKeySequence(tr("Delete")), this);*/ - //Create the filesystem watcher - watcher = new QFileSystemWatcher(this); - synctimer = new QTimer(this); - synctimer->setInterval(300); // 300 millisecond pause (combine simultaneous signals from the watcher) - synctimer->setSingleShot(true); - //Now update the rest of the UI - canmodify = false; //initial value - contextMenu = new QMenu(this); - setDateFormat(); - setShowDetails(true); - setShowThumbnails(true); - UpdateIcons(); - UpdateText(); - setupConnections(); -} - -DirWidget::~DirWidget(){ - stopload = true; //just in case another thread is still loading/running -} - -void DirWidget::setFocusLineDir() { - line_dir->setFocus(); - line_dir->selectAll(); -} - -void DirWidget::cleanup(){ - stopload = true; //just in case another thread is still loading/running - if(thumbThread.isRunning()){ thumbThread.waitForFinished(); } //this will stop really quickly with the flag set -} - -void DirWidget::ChangeDir(QString dirpath){ - stopload = true; //just in case it is still loading - emit LoadDirectory(ID, dirpath); -} - -void DirWidget::setDirCompleter(QCompleter *comp){ - line_dir->setCompleter(comp); -} - -QString DirWidget::id(){ - return ID; -} - -QString DirWidget::currentDir(){ - return CDIR; -} - -void DirWidget::setShowDetails(bool show){ - if(show!=showDetails){ - //View about to change - ensure the selection gets transferred too - tmpSel = currentSelection(); - } - showDetails = show; - listWidget->setVisible(!showDetails); - treeWidget->setVisible(showDetails); - this->refresh(); -} - -void DirWidget::setShowSidebar(bool show){ - ui->group_actions->setVisible(show); -} - -void DirWidget::setShowThumbnails(bool show){ - showThumbs = show; - this->refresh(); -} - -void DirWidget::setDetails(QList<DETAILTYPES> list){ - listDetails = list; - //Need to re-create the header item as well - CQTreeWidgetItem *it = new CQTreeWidgetItem(); - int nmcol = -1; int typecol = -1; - for(int t=0; t<listDetails.length(); t++){ - switch(listDetails[t]){ - case NAME: - it->setText(t,tr("Name")); - nmcol = t; - break; - case SIZE: - it->setText(t,tr("Size")); - break; - case TYPE: - it->setText(t, tr("Type")); - typecol = t; - break; - case DATEMOD: - it->setText(t, tr("Date Modified") ); - break; - case DATECREATE: - it->setText(t, tr("Date Created") ); - break; - } - } - treeWidget->setHeaderItem(it); - //Now reset the sorting (alphabetically, dirs first) - if(nmcol>=0){ treeWidget->sortItems(nmcol, Qt::AscendingOrder); } // sort by name - if(typecol>=0){ treeWidget->sortItems(typecol, Qt::AscendingOrder); } //sort by type first - - if(CDIR.isEmpty() || !showDetails){ return; } //don't need to reload dir if details are not visible - this->refresh(); -} - -void DirWidget::setThumbnailSize(int px){ - bool larger = listWidget->iconSize().height() < px; - listWidget->setIconSize(QSize(px,px)); - treeWidget->setIconSize(QSize(px,px)); - if(CDIR.isEmpty() || !larger ){ return; } //don't need to reload icons unless the new size is larger - this->refresh(); -} - -void DirWidget::setShowCloseButton(bool show){ - ui->actionClose_Browser->setVisible(show); -} - -QStringList DirWidget::getDateFormat() { - return date_format; -} - -// This function is only called if user changes sessionsettings. By doing so, operations like sorting by date -// are faster because the date format is already stored in DirWidget::date_format static variable -void DirWidget::setDateFormat() { - if(!date_format.isEmpty()) - date_format.clear(); - QSettings settings("LuminaDE","sessionsettings"); - // If value doesn't exist or is not setted, empty string is returned - date_format << settings.value("DateFormat").toString(); - date_format << settings.value("TimeFormat").toString(); -} - - -// ================ -// PUBLIC SLOTS -// ================ -void DirWidget::LoadDir(QString dir, QList<LFileInfo> list){ - if(dir.isEmpty()){ return; } //nothing to do - QTime time; - if(DEBUG){time.start(); } - qDebug() << "Load Dir:" << dir; - QString lastdir = CDIR; //for some checks later - QString lastbasedir = normalbasedir; - CDIR = dir; - if(CDIR.endsWith("/") && CDIR.length() > 1){ CDIR.chop(1); } - CLIST = list; //save for later - canmodify = QFileInfo(CDIR).isWritable(); - if(DEBUG){ qDebug() << "Clear UI:" <<time.elapsed(); } - //Clear the status text - if(!canmodify){ui->label_status->setText(tr("(Limited Access) ")); } - else{ ui->label_status->setText(""); } - //Hide the extra buttons for a moment - ui->tool_goToPlayer->setVisible(false); - ui->tool_goToImages->setVisible(false); - ui->tool_new_dir->setVisible(canmodify); - ui->tool_new_file->setVisible(canmodify); - //Set the drag/drop info as appripriate - if(canmodify){ - listWidget->setWhatsThis(CDIR); - treeWidget->setWhatsThis(CDIR); - }else{ - listWidget->setWhatsThis(""); - treeWidget->setWhatsThis(""); - } - bool updateThumbs = (lastdir != CDIR); - //Determine if this is an internal ZFS snapshot - bool loadsnaps = false; - if(DEBUG){ qDebug() << "Load Snap Info:" << time.elapsed(); } - if( dir.contains(ZSNAPDIR) ){ - //This is a zfs snapshot - only update the saved paths necessary to rotate between snapshots/system - snaprelpath = dir.section(ZSNAPDIR,1,1000).section("/",1,1000); //the relative path inside the snapshot - if(snaprelpath.endsWith("/")){ snaprelpath.chop(1); } - normalbasedir = dir.section(ZSNAPDIR,0,0)+"/"+snaprelpath; //Update the new base directory - if(normalbasedir.endsWith("/")){ normalbasedir.chop(1); } - line_dir->setText(normalbasedir); - //See if this was a manual move to the directory, or an internal move - QString tmp = dir.section(ZSNAPDIR,0,0); - if(tmp != snapbasedir.section(ZSNAPDIR,0,0)){ - loadsnaps = true; //different snapshot loaded - need to update internally - } - }else{ - //This is a normal directory - prompt for snapshot information - line_dir->setText(CDIR); - normalbasedir = CDIR; - if(!snapbasedir.isEmpty()){ watcher->removePath(snapbasedir); } - snapbasedir.clear(); - loadsnaps = true; - } - if(loadsnaps){ - //kick this off while still loading the dir contents - ui->group_snaps->setEnabled(false); //to prevent the snap updates to be automatically used - ui->group_snaps->setVisible(false); - ui->slider_snap->setRange(1,1); - emit findSnaps(ID, normalbasedir); - } - - if(DEBUG){ qDebug() << "Update History:" <<time.elapsed(); } - //Now update the history for this browser - //qDebug() << "History:" << history << normalbasedir << lastbasedir; - if(!history.isEmpty() && history.last() == normalbasedir && lastbasedir!=normalbasedir ){ - //We went back one - remove this from the history - history.takeLast(); - ui->actionBack->setEnabled(!history.isEmpty()); - //qDebug() << " - Duplicate: removed item"; - }else if(lastbasedir!=normalbasedir){ //not a refresh or internal snapshot change - //qDebug() << " - New History Item:" << normalbasedir; - history << normalbasedir; - ui->actionBack->setEnabled(history.length()>1); - } - if(DEBUG){ qDebug() << "Update Watcher:" << time.elapsed(); } - //Clear the current watcher - if(!watcher->directories().isEmpty()){ watcher->removePaths(watcher->directories()); } - if(!watcher->files().isEmpty()){ watcher->removePaths(watcher->files()); } - watcher->addPath(CDIR); - // add sessionsettings to watcher so date_format can be update based on user settings - watcher->addPath(sessionsettings_config_file); - ui->actionStopLoad->setVisible(true); - stopload = false; - //Clear the display widget (if a new directory) - if(DEBUG){ qDebug() << "Clear Browser Widget:" << time.elapsed(); } - double scrollpercent = -1; - if(updateThumbs){ needThumbs.clear(); } - if(lastbasedir != normalbasedir){ - if(showDetails){ treeWidget->clear(); } - else{ listWidget->clear(); } - QApplication::processEvents(); //make sure it is cleared right away - }else{ - //Need to be smarter about which items need to be removed - // - compare the old/new lists and remove any items not in the new listing (new items taken care of below) - QStringList newfiles; //just the filenames - for(int i=0; i<CLIST.length(); i++){ newfiles << CLIST[i].fileName(); } - if(showDetails){ - for(int i=0; i<treeWidget->topLevelItemCount(); i++){ - if( !newfiles.contains(treeWidget->topLevelItem(i)->whatsThis(0).section("/",-1)) ){ - if(!updateThumbs){ needThumbs.removeAll( treeWidget->topLevelItem(i)->whatsThis(0).section("::::",1,50)); } - delete treeWidget->takeTopLevelItem(i); - i--; - } - } - QApplication::processEvents(); //make sure the scrollbar is up to date after removals - scrollpercent = treeWidget->verticalScrollBar()->value()/( (double) treeWidget->verticalScrollBar()->maximum()); - }else{ - for(int i=0; i<listWidget->count(); i++){ - if( !newfiles.contains(listWidget->item(i)->text()) ){ - if(!updateThumbs){ needThumbs.removeAll( listWidget->item(i)->whatsThis().section("::::",1,50)); } - delete listWidget->takeItem(i); - i--; - } - } - QApplication::processEvents(); //make sure the scrollbar is up to date after removals - scrollpercent = listWidget->horizontalScrollBar()->value()/( (double) listWidget->horizontalScrollBar()->maximum()); - } - } //end check for CDIR reload - //Now fill the display widget - bool hasimages, hasmultimedia; - hasimages = hasmultimedia = false; - int numdirs = 0; - qint64 filebytes = 0; - //Setup the timer to see when we should process events - /*QTimer updatetime; - updatetime.setInterval(1000); //1 second updates - updatetime.setSingleShot(true); - updatetime.start();*/ - QTime updatetime = QTime::currentTime().addMSecs(500); - if(DEBUG){ qDebug() << "Start Loop over items:" << time.elapsed(); } - for(int i=0; i<list.length(); i++){ - if(stopload){ ui->actionStopLoad->setVisible(false); return; } //stop right now - if(!hasimages && list[i].isImage()){ hasimages = true; ui->tool_goToImages->setVisible(true); } - else if(!hasmultimedia && list[i].isAVFile()){ hasmultimedia = true; ui->tool_goToPlayer->setVisible(true); } - //Update statistics - if(list[i].isDir()){ numdirs++; } - else{ filebytes += list[i].size(); } - watcher->addPath(list[i].absoluteFilePath()); - if(showDetails){ - //Now create all the individual items for the details tree - CQTreeWidgetItem *it; - bool addnew = false; - //See if an item already exists for this file - QList<QTreeWidgetItem*> items = treeWidget->findItems(list[i].fileName(),Qt::MatchExactly,0); //NOTE: This requires column 0 to be the name - if(items.isEmpty()){ - it = new CQTreeWidgetItem(); - addnew = true; - }else{ - // Safe downcasting because CQTreeWidgetItem only redefines the virtual function bool opearot<. Not new methos added. - it = static_cast<CQTreeWidgetItem *> (items.first()); - } - //Now update the entry contents - it->setWhatsThis(0, QString(canmodify ? "cut": "copy")+"::::"+list[i].absoluteFilePath()); - for(int t=0; t<listDetails.length(); t++){ - switch(listDetails[t]){ - case NAME: - it->setText(t,list[i].fileName()); - it->setStatusTip(t, list[i].fileName()); - //Since the icon/image is based on the filename - only update this for a new item - // (This is the slowest part of the routine) - if(list[i].isImage()&& (addnew || updateThumbs)){ - if(showThumbs){ - it->setIcon(t, LXDG::findIcon("fileview-preview","image-x-generic") ); - needThumbs << list[i].absoluteFilePath(); - }else{ it->setIcon(t, LXDG::findIcon(list[i].iconfile(),"image-x-generic") ); } - }else if(addnew){ - it->setIcon(t, LXDG::findIcon(list[i].iconfile(),"unknown") ); - } - break; - case SIZE: - if(!list[i].isDir()){ - it->setText(t, LUtils::BytesToDisplaySize(list[i].size()) ); - } - break; - case TYPE: - it->setText(t, list[i].mimetype()); - break; - case DATEMOD: - { - QStringList datetime_format = getDateFormat(); - // Save datetime in WhatThis value. Lately will be used by CQTreeWidgetItem for sorting by date - it->setWhatsThis(t, list[i].lastModified().toString("yyyyMMddhhmmsszzz")); - // Default configurition. Fallback to Qt::DefaultLocaleShortDate for formats - if(datetime_format.at(0).isEmpty() && datetime_format.at(1).isEmpty()) - it->setText(t, list[i].lastModified().toString(Qt::DefaultLocaleShortDate) ); - // Date is setted but time not. Time goes to default - else if(!datetime_format.at(0).isEmpty() && datetime_format.at(1).isEmpty()) - it->setText(t, list[i].lastModified().date().toString(datetime_format.at(0)) + " " + list[i].lastModified().time().toString(Qt::DefaultLocaleShortDate)); - // Time is setted but date not. Date goes to default - else if(datetime_format.at(0).isEmpty() && !datetime_format.at(1).isEmpty()) - it->setText(t, list[i].lastModified().date().toString(Qt::DefaultLocaleShortDate) + " " + list[i].lastModified().time().toString(datetime_format.at(1))); - // Both time and date setted. - else - it->setText(t, list[i].lastModified().date().toString(datetime_format.at(0)) + " " + list[i].lastModified().time().toString(datetime_format.at(1))); - break; - } - case DATECREATE: - { - QStringList datetime_format = getDateFormat(); - it->setWhatsThis(DATECREATE, list[i].lastModified().toString("yyyyMMddhhmmsszzz")); - if(datetime_format.at(0).isEmpty() && datetime_format.at(1).isEmpty()) - it->setText(t, list[i].lastModified().toString(Qt::DefaultLocaleShortDate) ); - else if(!datetime_format.at(0).isEmpty() && datetime_format.at(1).isEmpty()) - it->setText(t, list[i].lastModified().date().toString(datetime_format.at(0)) + " " + list[i].lastModified().time().toString(Qt::DefaultLocaleShortDate)); - else if(datetime_format.at(0).isEmpty() && !datetime_format.at(1).isEmpty()) - it->setText(t, list[i].lastModified().date().toString(Qt::DefaultLocaleShortDate) + " " + list[i].lastModified().time().toString(datetime_format.at(1))); - else - it->setText(t, list[i].lastModified().date().toString(datetime_format.at(0)) + " " + list[i].lastModified().time().toString(datetime_format.at(1))); - break; - } - } - } - if(addnew){ treeWidget->addTopLevelItem(it); } - if(tmpSel.contains(list[i].absoluteFilePath())){ it->setSelected(true); } - if(lastdir == CDIR+"/"+list[i].fileName()){ - treeWidget->setCurrentItem(it); - treeWidget->scrollToItem(it); - } - }else{ - //Create all the individual items for the basic list - QListWidgetItem *it; - //See if there is an existing item to re-use - bool addnew = false; - QList<QListWidgetItem*> items = listWidget->findItems(list[i].fileName(), Qt::MatchExactly); - if(items.isEmpty()){ - it = new QListWidgetItem(); - addnew = true; - }else{ it = items.first(); } - - it->setWhatsThis( QString(canmodify ? "cut": "copy")+"::::"+list[i].absoluteFilePath()); //used for drag and drop - it->setText(list[i].fileName()); - it->setStatusTip(list[i].fileName()); - //Since the icon/image is based on the filename - only update this for a new items (non-thumbnail) - // (This is the slowest part of the routine) - if(list[i].isImage() && (addnew || updateThumbs) ){ - if(showThumbs){ - it->setIcon(LXDG::findIcon("fileview-preview","image-x-generic") ); - needThumbs << list[i].absoluteFilePath(); - }else{ it->setIcon(LXDG::findIcon(list[i].iconfile(),"image-x-generic") ); } - }else if(addnew){ - it->setIcon(LXDG::findIcon(list[i].iconfile(),"unknown") ); - } - listWidget->addItem(it); - if(tmpSel.contains(list[i].absoluteFilePath())){ it->setSelected(true); } - if(lastdir == CDIR+"/"+list[i].fileName()){ - listWidget->setCurrentItem(it); - listWidget->scrollToItem(it); - } - } - if(QTime::currentTime() > updatetime){ QApplication::processEvents(); updatetime = QTime::currentTime().addMSecs(500); }//keep the UI snappy while loading a directory - if(DEBUG){ qDebug() << " - item finished:" << i << time.elapsed(); } - } - tmpSel.clear(); - if(DEBUG){ qDebug() << "Done with item loop:" << time.elapsed() << list.length(); } - ui->actionStopLoad->setVisible(false); - //Another check to ensure the current item is visible (or return to the same scroll position) - if(stopload){ return; } //stop right now - if(scrollpercent<0){ - if(showDetails){ - for(int t=0; t<treeWidget->columnCount(); t++){treeWidget->resizeColumnToContents(t); } - if(treeWidget->currentItem()!=0){ treeWidget->scrollToItem(treeWidget->currentItem()); } - }else{ - if(listWidget->currentItem()!=0){ listWidget->scrollToItem(listWidget->currentItem()); } - } - }else{ - if(showDetails){ - treeWidget->verticalScrollBar()->setValue( qRound(treeWidget->verticalScrollBar()->maximum()*scrollpercent) ); - }else{ - listWidget->horizontalScrollBar()->setValue( qRound(listWidget->horizontalScrollBar()->maximum()*scrollpercent) ); - } - } - - - if(stopload){ return; } //stop right now - if(DEBUG){ qDebug() << "Assemble Status Message:" << time.elapsed(); } - //Assemble any status message - QString stats = QString(tr("Capacity: %1")).arg(LOS::FileSystemCapacity(CDIR)); - if(list.length()>0){ - stats.prepend("\t"); - if(numdirs < list.length()){ - //Has Files - stats.prepend( QString(tr("Files: %1 (%2)")).arg(QString::number(list.length()-numdirs), LUtils::BytesToDisplaySize(filebytes)) ); - } - if(numdirs > 0){ - //Has Dirs - if(numdirs<list.length()){ stats.prepend(" / "); }//has files output already - stats.prepend( QString(tr("Dirs: %1")).arg(QString::number(numdirs)) ); - } - - } - if(stopload){ return; } //stop right now - if(!canmodify){ stats.prepend(tr("(Limited Access) ")); } - ui->label_status->setText( stats.simplified() ); - if(DEBUG){ qDebug() << "DONE:" << time.elapsed(); } - if(showThumbs){ thumbThread = QtConcurrent::run(this, &DirWidget::startLoadThumbs); } -} - -void DirWidget::LoadSnaps(QString basedir, QStringList snaps){ - //Save these value internally for use later - qDebug() << "ZFS Snapshots available:" << basedir << snaps; - snapbasedir = basedir; - snapshots = snaps; - if(!snapbasedir.isEmpty()){ watcher->addPath(snapbasedir); } //add this to the watcher in case snapshots get created/removed - //Now update the UI as necessary - if(ui->tool_snap->menu()==0){ - ui->tool_snap->setMenu(new QMenu(this)); - connect(ui->tool_snap->menu(), SIGNAL(triggered(QAction*)), this, SLOT(direct_snap_selected(QAction*)) ); - } - ui->tool_snap->menu()->clear(); - for(int i=0; i<snapshots.length(); i++){ - QAction *tmp = ui->tool_snap->menu()->addAction(snapshots[i]); - tmp->setWhatsThis(snapshots[i]); - } - ui->slider_snap->setRange(0, snaps.length()); - if(CDIR.contains(ZSNAPDIR)){ - //The user was already within a snapshot - figure out which one and set the slider appropriately - int index = snaps.indexOf( CDIR.section(ZSNAPDIR,1,1).section("/",0,0) ); - if(index < 0){ index = snaps.length(); } //unknown - load the system (should never happen) - ui->slider_snap->setValue(index); - }else{ - ui->slider_snap->setValue(snaps.length()); //last item (normal system) - } - on_slider_snap_valueChanged(); - QApplication::processEvents(); //let the slider changed signal get thrown away before we re-enable the widget - ui->group_snaps->setEnabled(!snaps.isEmpty()); - ui->group_snaps->setVisible(!snaps.isEmpty()); - ui->tool_snap_newer->setEnabled(ui->slider_snap->value() < ui->slider_snap->maximum()); - ui->tool_snap_older->setEnabled(ui->slider_snap->value() > ui->slider_snap->minimum()); -} - -void DirWidget::refresh(){ - if(!CDIR.isEmpty() && ~ID.isEmpty()){ - stopload = true; //just in case it is still loading - emit LoadDirectory(ID, CDIR); - } -} - -void DirWidget::refreshButtons(){ - SelectionChanged(); -} - -//Theme change functions -void DirWidget::UpdateIcons(){ - //ui->tool_addNewFile->setIcon( LXDG::findIcon("document-new","")); - //ui->tool_addToDir->setIcon( LXDG::findIcon("folder-new","") ); - - //Snapshot buttons - ui->tool_snap_newer->setIcon(LXDG::findIcon("go-next-view","") ); - ui->tool_snap_older->setIcon(LXDG::findIcon("go-previous-view","") ); - //Bottom-Action Buttons - ui->tool_goToImages->setIcon( LXDG::findIcon("fileview-preview","") ); - ui->tool_goToPlayer->setIcon( LXDG::findIcon("applications-multimedia","") ); - ui->tool_new_file->setIcon( LXDG::findIcon("document-new","") ); - ui->tool_new_dir->setIcon( LXDG::findIcon("folder-new","") ); - //Side-Action Buttons - ui->tool_act_run->setIcon( LXDG::findIcon("run-build-file","") ); - ui->tool_act_runwith->setIcon( LXDG::findIcon("run-build-configure","") ); - ui->tool_act_cut->setIcon( LXDG::findIcon("edit-cut","") ); - ui->tool_act_copy->setIcon( LXDG::findIcon("edit-copy","") ); - ui->tool_act_paste->setIcon( LXDG::findIcon("edit-paste","") ); - ui->tool_act_rename->setIcon( LXDG::findIcon("edit-rename","") ); - ui->tool_act_rm->setIcon( LXDG::findIcon("edit-delete","") ); - ui->tool_act_fav->setIcon( LXDG::findIcon("bookmark-toolbar","") ); - //ToolBar Buttons - ui->actionBack->setIcon( LXDG::findIcon("go-previous","") ); - ui->actionUp->setIcon( LXDG::findIcon("go-up","") ); - ui->actionHome->setIcon( LXDG::findIcon("go-home","") ); - ui->actionStopLoad->setIcon( LXDG::findIcon("dialog-cancel","") ); - ui->actionClose_Browser->setIcon( LXDG::findIcon("dialog-close","") ); -} - -void DirWidget::UpdateText(){ - ui->retranslateUi(this); -} - -void DirWidget::UpdateButtons(){ - SelectionChanged(); -} - -//Keyboard Shortcuts triggered -void DirWidget::TryRenameSelection(){ - on_tool_act_rename_clicked(); -} - -void DirWidget::TryCutSelection(){ - on_tool_act_cut_clicked(); -} - -void DirWidget::TryCopySelection(){ - on_tool_act_copy_clicked(); -} - -void DirWidget::TryPasteSelection(){ - on_tool_act_paste_clicked(); -} - -void DirWidget::TryDeleteSelection(){ - on_tool_act_rm_clicked(); -} - -// ================= -// PRIVATE -// ================= -void DirWidget::setupConnections(){ - //Info routines - connect(treeWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OpenContextMenu()) ); - connect(listWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OpenContextMenu()) ); - connect(treeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(SelectionChanged()) ); - connect(listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(SelectionChanged()) ); - - //Activation routines - connect(treeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(on_tool_act_run_clicked()) ); - connect(treeWidget, SIGNAL(DataDropped(QString, QStringList)), this, SIGNAL(PasteFiles(QString, QStringList)) ); - connect(listWidget, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(on_tool_act_run_clicked()) ); - connect(listWidget, SIGNAL(DataDropped(QString, QStringList)), this, SIGNAL(PasteFiles(QString, QStringList)) ); - connect(line_dir, SIGNAL(returnPressed()), this, SLOT(dir_changed()) ); - - //Keyboard Shortcuts - /*connect(copyFilesShort, SIGNAL(activated()), this, SLOT( on_tool_act_copy_clicked() ) ); - connect(cutFilesShort, SIGNAL(activated()), this, SLOT( on_tool_act_cut_clicked() ) ); - connect(pasteFilesShort, SIGNAL(activated()), this, SLOT( on_tool_act_paste_clicked() ) ); - connect(deleteFilesShort, SIGNAL(activated()), this, SLOT( on_tool_act_rm_clicked() ) );*/ - - //Filesystem Watcher - connect(watcher, SIGNAL(directoryChanged(const QString&)), this, SLOT(startSync(const QString &)) ); - connect(watcher, SIGNAL(fileChanged(const QString&)), this, SLOT(startSync(const QString &)) ); //just in case - connect(synctimer, SIGNAL(timeout()), this, SLOT(refresh()) ); - - //Thumbnail loader - connect(this, SIGNAL(ThumbLoaded(QString, QIcon)), this, SLOT(showThumb(QString, QIcon)) ); -} - -QStringList DirWidget::currentSelection(){ - QStringList out; - if(showDetails){ - QList<QTreeWidgetItem*> sel = treeWidget->selectedItems(); - for(int i=0; i<sel.length(); i++){ - out << sel[i]->whatsThis(0).section("::::",1,100); //absolute file path - } - }else{ - QList<QListWidgetItem*> sel = listWidget->selectedItems(); - for(int i=0; i<sel.length(); i++){ - out << sel[i]->whatsThis().section("::::",1,100); //absolute file path - } - } - out.removeDuplicates(); - return out; -} - -// ================= -// PRIVATE SLOTS -// ================= -void DirWidget::startLoadThumbs(){ - //This just runs through the dir and loads all the thumbnails as needed - if(DEBUG){ qDebug() << "Start Loading Thumbnails:" << needThumbs; } - if(needThumbs.isEmpty()){ return; } - needThumbs.removeDuplicates(); //just in case - //QTime updatetime = QTime::currentTime().addMSecs(500); - while(!needThumbs.isEmpty() && !stopload){ - QString file = needThumbs.takeFirst(); - QIcon ico(QPixmap(file).scaled(listWidget->iconSize(),Qt::IgnoreAspectRatio, Qt::FastTransformation) ); - emit ThumbLoaded(file, ico); - } -} - -void DirWidget::showThumb(QString file, QIcon ico){ - if(showDetails){ - //Use the tree widget - QList<QTreeWidgetItem*> items = treeWidget->findItems(file.section("/",-1), Qt::MatchExactly); - if(items.isEmpty() || stopload){ return; } //invalid item for some reason - QTreeWidgetItem *it = items.first(); - it->setIcon(0, ico ); - }else{ - //Use the list widget - QList<QListWidgetItem*> items = listWidget->findItems(file.section("/",-1), Qt::MatchExactly); - if(items.isEmpty() || stopload){ return; } //invalid item for some reason - if(stopload){ return; } //stop right now - QListWidgetItem *it = items.first(); - it->setIcon(ico); - } -} - -//UI BUTTONS -// -- Left Action Buttons -void DirWidget::on_tool_act_cut_clicked(){ - QStringList sel = currentSelection(); - qDebug() << "Cutting Items to clipboard:" << sel; - if(sel.isEmpty()){ return; } - emit CutFiles(sel); -} - -void DirWidget::on_tool_act_copy_clicked(){ - QStringList sel = currentSelection(); - if(sel.isEmpty()){ return; } - qDebug() << "Copying Items to clipboard:" << sel; - emit CopyFiles(sel); -} - -void DirWidget::on_tool_act_fav_clicked(){ - QStringList sel = currentSelection(); - if(sel.isEmpty()){ return; } - - emit FavoriteFiles(sel); -} - -void DirWidget::on_tool_act_paste_clicked(){ - qDebug() << "Pasting Items from clipboard:" << CDIR; - emit PasteFiles(CDIR, QStringList()); //use the clipboard for pasting -} - -void DirWidget::on_tool_act_rename_clicked(){ - QStringList sel = currentSelection(); - if(sel.isEmpty()){ return; } - emit RenameFiles(sel); -} - -void DirWidget::on_tool_act_rm_clicked(){ - QStringList sel = currentSelection(); - if(sel.isEmpty()){ return; } - qDebug() << "Deleting selected Items:" << sel; - emit RemoveFiles(sel); -} - -void DirWidget::on_tool_act_run_clicked(){ - QStringList sel = currentSelection(); - if(sel.isEmpty()){ return; } - QStringList dirs; - for(int i=0; i<sel.length(); i++){ - if(QFileInfo(sel[i]).isDir()){ - dirs << sel[i]; - }else{ - QProcess::startDetached("lumina-open \""+sel[i]+"\""); - } - } - if(!dirs.isEmpty()){ - stopload = true; //just in case it is still loading - emit LoadDirectory(ID, dirs.takeFirst()); //load the first directory in this widget - } - if(!dirs.isEmpty()){ - emit OpenDirectories(dirs); - } -} - -void DirWidget::on_tool_act_runwith_clicked(){ - QStringList sel = currentSelection(); - if(sel.isEmpty()){ return; } - for(int i=0; i<sel.length(); i++){ - QProcess::startDetached("lumina-open -select \""+sel[i]+"\""); //use absolute paths - } -} - -// -- Bottom Action Buttons -void DirWidget::on_tool_goToImages_clicked(){ - QStringList sel = currentSelection(); - if(sel.isEmpty()){ emit ViewFiles(CLIST); } - else{ - //Just use the files from the current selection - LFileInfoList list; - for(int i=0; i<CLIST.length(); i++){ - if(CLIST[i].isImage() && sel.contains(CLIST[i].absoluteFilePath()) ){ - list << CLIST[i]; //add to the list - } - } - if(!list.isEmpty()){ emit ViewFiles(list); } - else{ emit ViewFiles(CLIST); } //invalid file(s) selected - just do everything - } -} - -void DirWidget::on_tool_goToPlayer_clicked(){ - QStringList sel = currentSelection(); - if(sel.isEmpty()){ emit PlayFiles(CLIST); } - else{ - //Just use the files from the current selection - LFileInfoList list; - for(int i=0; i<CLIST.length(); i++){ - if(CLIST[i].isAVFile() && sel.contains(CLIST[i].absoluteFilePath()) ){ - list << CLIST[i]; //add to the list - } - } - if(!list.isEmpty()){ emit PlayFiles(list); } - else{ emit PlayFiles(CLIST); } //invalid file(s) selected - just do everything - } -} - -void DirWidget::on_tool_new_file_clicked(){ - if(!canmodify){ return; } //cannot create anything here - //Prompt for the new filename - bool ok = false; - QString newdocument = QInputDialog::getText(this, tr("New Document"), tr("Name:"), QLineEdit::Normal, "", \ - &ok, 0, Qt::ImhFormattedNumbersOnly | Qt::ImhUppercaseOnly | Qt::ImhLowercaseOnly); - if(!ok || newdocument.isEmpty()){ return; } - //Create the empty file - QString full = CDIR; - if(!full.endsWith("/")){ full.append("/"); } - QFile file(full+newdocument); - if(file.open(QIODevice::ReadWrite)){ - //If successfully opened, it has created a blank file - file.close(); - }else{ - QMessageBox::warning(this, tr("Error Creating Document"), tr("The document could not be created. Please ensure that you have the proper permissions.")); - } - //just in case the watcher does not work for this filesystem -queue up a sync - if(!synctimer->isActive()){ synctimer->start(); } -} - -void DirWidget::on_tool_new_dir_clicked(){ - if(!canmodify){ return; } //cannot create anything here - //Prompt for the new dir name - bool ok = false; - QString newdir = QInputDialog::getText(this, tr("New Directory"), tr("Name:"), QLineEdit::Normal, "", \ - &ok, 0, Qt::ImhFormattedNumbersOnly | Qt::ImhUppercaseOnly | Qt::ImhLowercaseOnly); - if(!ok || newdir.isEmpty()){ return; } - //Now create the new dir - QString full = CDIR; - if(!full.endsWith("/")){ full.append("/"); } - QDir dir(full); //open the current dir - full.append(newdir); //append the new name to the current dir - //Verify that the new dir does not already exist - if(dir.exists(full)){ - QMessageBox::warning(this, tr("Invalid Name"), tr("A file or directory with that name already exists! Please pick a different name.")); - QTimer::singleShot(0,this, SLOT(on_tool_addToDir_clicked()) ); //repeat this function - }else{ - if(!dir.mkdir(newdir) ){ - 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.")); - } - } - //just in case the watcher does not work for this filesystem -queue up a sync - if(!synctimer->isActive()){ synctimer->start(); } -} - -// -- Top Snapshot Buttons -void DirWidget::on_tool_snap_newer_clicked(){ - ui->slider_snap->setValue( ui->slider_snap->value()+1 ); -} - -void DirWidget::on_tool_snap_older_clicked(){ - ui->slider_snap->setValue( ui->slider_snap->value()-1 ); -} - -void DirWidget::on_slider_snap_valueChanged(int val){ - bool labelsonly = false; - if(val==-1){ val = ui->slider_snap->value(); labelsonly=true; } - //Update the snapshot interface - ui->tool_snap_newer->setEnabled(val < ui->slider_snap->maximum()); - ui->tool_snap_older->setEnabled(val > ui->slider_snap->minimum()); - if(val >= snapshots.length() || val < 0){ - ui->tool_snap->setText(tr("Current")); - }else if(QFile::exists(snapbasedir+snapshots[val])){ - ui->tool_snap->setText( QFileInfo(snapbasedir+snapshots[val]).lastModified().toString(Qt::DefaultLocaleShortDate) ); - } - //Exit if a non-interactive snapshot change - if(!ui->group_snaps->isEnabled() || labelsonly){ return; } //internal change - do not try to change the actual info - //Determine which snapshot is now selected - QString dir; - if(DEBUG){ qDebug() << "Changing snapshot:" << CDIR << val << snapbasedir; } - stopload = true; //stop any currently-loading procedures - if(val >= snapshots.length() || val < 0){ //active system selected - if(DEBUG){ qDebug() << " - Load Active system:" << normalbasedir; } - dir = normalbasedir; - }else{ - dir = snapbasedir+snapshots[val]+"/"; - if(!QFile::exists(dir)){ - //This snapshot must have been removed in the background by pruning tools - // move to a newer snapshot or the current base dir as necessary - qDebug() << "Snapshot no longer available:" << dir; - qDebug() << " - Reloading available snapshots"; - emit findSnaps(ID, normalbasedir); - return; - } - //if(snaprelpath.isEmpty()){ - //Need to figure out the relative path within the snapshot - snaprelpath = normalbasedir.section(snapbasedir.section(ZSNAPDIR,0,0), 1,1000); - if(DEBUG){ qDebug() << " - new snapshot-relative path:" << snaprelpath; } - //} - dir.append(snaprelpath); - dir.replace("//","/"); //just in case any duplicate slashes from all the split/combining - if(DEBUG){ qDebug() << " - Load Snapshot:" << dir; } - } - //Make sure this directory exists, and back up as necessary - if(dir.isEmpty()){ return; } - //Load the newly selected snapshot - stopload = true; //just in case it is still loading - emit LoadDirectory(ID, dir); -} - -void DirWidget::direct_snap_selected(QAction *act){ - QString snap = act->whatsThis(); - int val = snapshots.indexOf(snap); - if(val<0){ return; } - else{ ui->slider_snap->setValue(val); } -} - -//Top Toolbar buttons -void DirWidget::on_actionBack_triggered(){ - if(history.isEmpty()){ return; } //cannot do anything - QString dir = history.takeLast(); - //qDebug() << "Go Back:" << dir << normalbasedir << history.last(); - if(dir == normalbasedir){ - dir = history.takeLast(); - } - stopload = true; //just in case it is still loading - emit LoadDirectory(ID, dir); -} - -void DirWidget::on_actionUp_triggered(){ - QString dir = CDIR.section("/",0,-2); - if(dir.isEmpty()) - dir = "/"; - //Quick check to ensure the directory exists - while(!QFile::exists(dir) && !dir.isEmpty()){ - dir = dir.section("/",0,-2); //back up one additional dir - } - stopload = true; //just in case it is still loading - emit LoadDirectory(ID, dir); -} - -void DirWidget::on_actionHome_triggered(){ - stopload = true; //just in case it is still loading - emit LoadDirectory(ID, QDir::homePath()); -} - -void DirWidget::on_actionStopLoad_triggered(){ - stopload = true; - ui->actionStopLoad->setVisible(false); -} - -void DirWidget::dir_changed(){ - QString dir = line_dir->text().simplified(); - //Run the dir through the user-input checks - dir = LUtils::PathToAbsolute(dir); - qDebug() << "Dir:" << dir; - //Quick check to ensure the directory exists - while(!QFile::exists(dir) && !dir.isEmpty()){ - dir = dir.section("/",0,-2); //back up one additional dir - } - qDebug() << " - Now Dir:" << dir; - stopload = true; //just in case it is still loading - emit LoadDirectory(ID, dir); -} - -void DirWidget::on_actionClose_Browser_triggered(){ - emit CloseBrowser(ID); -} - -// - Other Actions without a specific button on the side -void DirWidget::fileCheckSums(){ - QStringList files = currentSelection(); - if(files.isEmpty()){ return; } - qDebug() << "Run Checksums:" << files; - QStringList info = LOS::Checksums(files); - qDebug() << " - Info:" << info; - if(info.isEmpty() || (info.length() != files.length()) ){ return; } - for(int i=0; i<info.length(); i++){ - info[i] = QString("%2\n\t(%1)").arg(files[i].section("/",-1), info[i]); - } - ScrollDialog dlg(this); - dlg.setWindowTitle( tr("File Checksums:") ); - dlg.setWindowIcon( LXDG::findIcon("document-encrypted","") ); - dlg.setText(info.join("\n")); - dlg.exec(); - /*QMessageBox dlg(this); - dlg.setWindowFlags( Qt::Dialog ); - dlg.setWindowTitle( tr("File Checksums") ); - dlg.setDetailedText(info.join("\n")); - dlg.exec();*/ - //QMessageBox::information(this, tr("File Checksums"), info.join("\n") ); -} - -void DirWidget::fileProperties(){ - QStringList sel = currentSelection(); - if(sel.isEmpty()){ return; } - if(!LUtils::isValidBinary("lumina-fileinfo")){ - //It should never get to this point due to checks earlier - but just in case... - QMessageBox::warning(this, tr("Missing Utility"), tr("The \"lumina-fileinfo\" utility could not be found on the system. Please install it first.") ); - return; - } - for(int i=0; i<sel.length(); i++){ - QProcess::startDetached("lumina-fileinfo \""+sel[i]+"\""); //use absolute paths - } -} - -void DirWidget::openTerminal(){ - emit LaunchTerminal(CDIR); -} - -//Browser Functions -void DirWidget::OpenContextMenu(){ - //First generate the context menu based on the selection - QStringList sel = currentSelection(); - contextMenu->clear(); - if(!sel.isEmpty()){ - contextMenu->addAction(LXDG::findIcon("run-build-file",""), tr("Open"), this, SLOT(on_tool_act_run_clicked()) ); - contextMenu->addAction(LXDG::findIcon("run-build-configure",""), tr("Open With..."), this, SLOT(on_tool_act_runwith_clicked()) ); - - contextMenu->addAction(LXDG::findIcon("edit-rename",""), tr("Rename..."), this, SLOT(on_tool_act_rename_clicked()) )->setEnabled(canmodify); - contextMenu->addAction(LXDG::findIcon("document-encrypted",""), tr("View Checksums..."), this, SLOT(fileCheckSums()) ); - contextMenu->addSeparator(); - } - //Now add the general selection options - contextMenu->addAction(LXDG::findIcon("edit-cut",""), tr("Cut Selection"), this, SLOT(on_tool_act_cut_clicked()) )->setEnabled(canmodify && !sel.isEmpty()); - contextMenu->addAction(LXDG::findIcon("edit-copy",""), tr("Copy Selection"), this, SLOT(on_tool_act_copy_clicked()) )->setEnabled(!sel.isEmpty()); - contextMenu->addAction(LXDG::findIcon("edit-paste",""), tr("Paste"), this, SLOT(on_tool_act_paste_clicked()) )->setEnabled(QApplication::clipboard()->mimeData()->hasFormat("x-special/lumina-copied-files") && canmodify); - contextMenu->addSeparator(); - contextMenu->addAction(LXDG::findIcon("edit-delete",""), tr("Delete Selection"), this, SLOT(on_tool_act_rm_clicked()) )->setEnabled(canmodify&&!sel.isEmpty()); - if(LUtils::isValidBinary("lumina-fileinfo")){ - contextMenu->addSeparator(); - contextMenu->addAction(LXDG::findIcon("edit-find-replace",""), tr("File Properties..."), this, SLOT(fileProperties()) )->setEnabled(!sel.isEmpty()); - } - contextMenu->addSeparator(); - contextMenu->addAction(LXDG::findIcon("system-search",""), tr("Open Terminal here"), this, SLOT(openTerminal())); - - //Now open the menu at the current cursor location - contextMenu->popup(QCursor::pos()); -} - -void DirWidget::SelectionChanged(){ - //Go through and enable/disable the buttons as necessary - bool hasselection = !currentSelection().isEmpty(); - ui->tool_act_copy->setEnabled(hasselection); - ui->tool_act_cut->setEnabled(hasselection && canmodify); - ui->tool_act_fav->setEnabled(hasselection); - ui->tool_act_paste->setEnabled(canmodify && QApplication::clipboard()->mimeData()->hasFormat("x-special/lumina-copied-files") ); - ui->tool_act_rename->setEnabled(hasselection && canmodify); - ui->tool_act_rm->setEnabled(hasselection && canmodify); - ui->tool_act_run->setEnabled(hasselection); - ui->tool_act_runwith->setEnabled(hasselection); -} - -void DirWidget::startSync(const QString &file){ - //Update date_format based on user settings - if(file == sessionsettings_config_file){ setDateFormat(); } - else if(file == snapbasedir){ emit findSnaps(ID, normalbasedir); } //snapshot list changed - else if(file == normalbasedir){ - if(synctimer->isActive()){ synctimer->stop(); } //already starting a sync - restart the timer - synctimer->start(); - }else{ - //Some file in the directory got changed - start the time for a dir reload - // -- This prevents a directory from refreshing constantly if a file within the directory is changing all the time (such as a log file) - if(!synctimer->isActive()){ synctimer->start(); } - } -} - -//==================== -// PROTECTED -//==================== -void DirWidget::mouseReleaseEvent(QMouseEvent *ev){ - static Qt::MouseButtons backmap = Qt::BackButton | Qt::ExtraButton5; - //qDebug() << "Mouse Click:" << ev->button(); - if(backmap.testFlag(ev->button())){ - ev->accept(); - on_actionBack_triggered(); - //}else if(ev->button()==Qt::ForwardButton()){ - //ev->accept(); - }else{ - ev->ignore(); //not handled here - } -} diff --git a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.h b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.h deleted file mode 100644 index 3ef9940b..00000000 --- a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.h +++ /dev/null @@ -1,229 +0,0 @@ -//=========================================== -// Lumina-DE source code -// Copyright (c) 2015, Ken Moore -// Available under the 3-clause BSD license -// See the LICENSE file for full details -//=========================================== -#ifndef _LUMINA_FM_DIRECTORY_BROWSER_WIDGET_H -#define _LUMINA_FM_DIRECTORY_BROWSER_WIDGET_H - -#include <QList> -#include <QWidget> -#include <QObject> -#include <QMenu> -#include <QToolBar> -#include <QLineEdit> -#include <QShortcut> -#include <QFileSystemWatcher> -#include <QTimer> -#include <QFuture> - -#include "../DirData.h" -#include "DDListWidgets.h" - -#define ZSNAPDIR QString("/.zfs/snapshot/") - -namespace Ui{ - class DirWidget; -}; - -class DirWidget : public QWidget{ - Q_OBJECT -public: - enum DETAILTYPES{ NAME, SIZE, TYPE, DATEMOD, DATECREATE}; - DirWidget(QString objID, QWidget *parent = 0); //needs a unique ID (to distinguish from other DirWidgets) - ~DirWidget(); - - void cleanup(); //called before the browser is closed down - - //Directory Managment - void ChangeDir(QString dirpath); - void setDirCompleter(QCompleter *comp); - - //Information - QString id(); - QString currentDir(); - - //View Settings - void setShowDetails(bool show); - void setShowSidebar(bool show); - void setShowThumbnails(bool show); - void setDetails(QList<DETAILTYPES> list); //Which details to show and in which order (L->R) - void setThumbnailSize(int px); - void setShowCloseButton(bool show); - void setFocusLineDir(); - - //Date format for show items - QStringList getDateFormat(); - void setDateFormat(); - -public slots: - void LoadDir(QString dir, LFileInfoList list); - void LoadSnaps(QString basedir, QStringList snaps); - - //Refresh options - void refresh(); //Refresh current directory - void refreshButtons(); //Refresh action buttons only - - //Theme change functions - void UpdateIcons(); - void UpdateText(); - - //Button updates - void UpdateButtons(); - - //Keyboard Shortcuts triggered - void TryRenameSelection(); - void TryCutSelection(); - void TryCopySelection(); - void TryPasteSelection(); - void TryDeleteSelection(); - -private: - Ui::DirWidget *ui; - QString ID, CDIR; //unique ID assigned by the parent and the current dir path - LFileInfoList CLIST; //current item list (snap or not) - QString normalbasedir, snapbasedir, snaprelpath; //for maintaining directory context while moving between snapshots - QStringList snapshots, needThumbs, tmpSel; - bool showDetails, showThumbs, canmodify, stopload; //which widget to use for showing items - QList<DETAILTYPES> listDetails; - QMenu *contextMenu; - QFuture<void> thumbThread; - //The Toolbar and associated items - QToolBar *toolbar; - QLineEdit *line_dir; - QStringList history; - //The drag and drop brower widgets - DDListWidget *listWidget; - DDTreeWidget *treeWidget; - - //Keyboard Shortcuts - //QShortcut *copyFilesShort, *cutFilesShort, *pasteFilesShort, *deleteFilesShort; - //Watcher to determine when the dir changes - QFileSystemWatcher *watcher; - QTimer *synctimer; - - //Functions for internal use - void setupConnections(); - QStringList currentSelection(); - QStringList date_format; - -private slots: - //Internal loading of thumbnails - void startLoadThumbs(); - void showThumb(QString file, QIcon ico); - - //UI BUTTONS/Actions - // -- Left Action Buttons - void on_tool_act_copy_clicked(); - void on_tool_act_cut_clicked(); - void on_tool_act_fav_clicked(); - void on_tool_act_paste_clicked(); - void on_tool_act_rename_clicked(); - void on_tool_act_rm_clicked(); - void on_tool_act_run_clicked(); - void on_tool_act_runwith_clicked(); - // -- Bottom Action Buttons - void on_tool_goToImages_clicked(); - void on_tool_goToPlayer_clicked(); - void on_tool_new_file_clicked(); - void on_tool_new_dir_clicked(); - // -- Top Snapshot Buttons - void on_tool_snap_newer_clicked(); - void on_tool_snap_older_clicked(); - void on_slider_snap_valueChanged(int val = -1); - void direct_snap_selected(QAction*); - - //Top Toolbar buttons - void on_actionBack_triggered(); - void on_actionUp_triggered(); - void on_actionHome_triggered(); - void on_actionStopLoad_triggered(); - void dir_changed(); //user manually changed the directory - void on_actionClose_Browser_triggered(); - - // - Other Actions without a specific button on the side - void fileCheckSums(); - void fileProperties(); - void openTerminal(); - - - //Browser Functions - void OpenContextMenu(); - void SelectionChanged(); - void startSync(const QString &file); //used internally to collect/pause before updating the dir - -signals: - //Directory loading/finding signals - void OpenDirectories(QStringList); //Directories to open in other tabs/columns - void LoadDirectory(QString, QString); //ID, dirpath (Directory to load here) - void findSnaps(QString, QString); //ID, dirpath (Request snapshot information for a directory) - void CloseBrowser(QString); //ID (Request that this browser be closed) - - //External App/Widget launching - void PlayFiles(LFileInfoList); //open in multimedia player - void ViewFiles(LFileInfoList); //open in slideshow - void LaunchTerminal(QString); //dirpath - - //System Interactions - void CutFiles(QStringList); //file selection - void CopyFiles(QStringList); //file selection - void PasteFiles(QString, QStringList); //current dir - void FavoriteFiles(QStringList); //file selection - void RenameFiles(QStringList); //file selection - void RemoveFiles(QStringList); //file selection - - //Internal thumbnail loading system (multi-threaded) - void ThumbLoaded(QString, QIcon); - -protected: - void mouseReleaseEvent(QMouseEvent *); - -}; - -/* - * Virtual class for managing the sort of folders/files items. The problem with base class is that it only manages texts fields and - * we have dates and sizes. - * - * On this class, we overwrite the function operator<. - */ - -class CQTreeWidgetItem : public QTreeWidgetItem { -public: - CQTreeWidgetItem(int type = Type) : QTreeWidgetItem(type) {} - CQTreeWidgetItem(const QStringList & strings, int type = Type) : QTreeWidgetItem(strings, type) {} - CQTreeWidgetItem(QTreeWidget * parent, int type = Type) : QTreeWidgetItem(parent, type) {} - CQTreeWidgetItem(QTreeWidget * parent, const QStringList & strings, int type = Type) : QTreeWidgetItem(parent, strings, type) {} - CQTreeWidgetItem(QTreeWidget * parent, QTreeWidgetItem * preceding, int type = Type) : QTreeWidgetItem(parent, preceding, type) {} - CQTreeWidgetItem(QTreeWidgetItem * parent, int type = Type) : QTreeWidgetItem(parent, type) {} - CQTreeWidgetItem(QTreeWidgetItem * parent, const QStringList & strings, int type = Type) : QTreeWidgetItem(parent, strings, type) {} - CQTreeWidgetItem(QTreeWidgetItem * parent, QTreeWidgetItem * preceding, int type = Type) : QTreeWidgetItem(parent, preceding, type) {} - virtual ~CQTreeWidgetItem() {} - inline virtual bool operator<(const QTreeWidgetItem &tmp) const { - int column = this->treeWidget()->sortColumn(); - // We are in date text - if(column == DirWidget::DATEMOD || column == DirWidget::DATECREATE) - return this->whatsThis(column) < tmp.whatsThis(column); - // We are in size text - else if(column == DirWidget::SIZE) { - QString text = this->text(column); - QString text_tmp = tmp.text(column); - double filesize, filesize_tmp; - // On folders, text is empty so we check for that - // In case we are in folders, we put -1 for differentiate of regular files with 0 bytes. - // Doing so, all folders we'll be together instead of mixing with files with 0 bytes. - if(text.isEmpty()) - filesize = -1; - else - filesize = LUtils::DisplaySizeToBytes(text); - if(text_tmp.isEmpty()) - filesize_tmp = -1; - else - filesize_tmp = LUtils::DisplaySizeToBytes(text_tmp); - return filesize < filesize_tmp; - } - // In other cases, we trust base class implementation - return QTreeWidgetItem::operator<(tmp); - } -}; -#endif diff --git a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.ui b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.ui deleted file mode 100644 index c5bf12c3..00000000 --- a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.ui +++ /dev/null @@ -1,527 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>DirWidget</class> - <widget class="QWidget" name="DirWidget"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>400</width> - <height>350</height> - </rect> - </property> - <property name="minimumSize"> - <size> - <width>350</width> - <height>0</height> - </size> - </property> - <property name="windowTitle"> - <string>Form</string> - </property> - <layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0" columnstretch="0,1"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="horizontalSpacing"> - <number>1</number> - </property> - <property name="verticalSpacing"> - <number>2</number> - </property> - <item row="0" column="0" rowspan="2" colspan="2"> - <layout class="QHBoxLayout" name="toolbar_layout"/> - </item> - <item row="3" column="0" colspan="2"> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QToolButton" name="tool_new_file"> - <property name="statusTip"> - <string>Create a new file</string> - </property> - <property name="text"> - <string>New File</string> - </property> - <property name="toolButtonStyle"> - <enum>Qt::ToolButtonTextBesideIcon</enum> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="tool_new_dir"> - <property name="statusTip"> - <string>Create a new directory</string> - </property> - <property name="text"> - <string>New Dir</string> - </property> - <property name="toolButtonStyle"> - <enum>Qt::ToolButtonTextBesideIcon</enum> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="tool_goToImages"> - <property name="statusTip"> - <string>Add selected images to slideshow</string> - </property> - <property name="text"> - <string>Slideshow</string> - </property> - <property name="iconSize"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - <property name="toolButtonStyle"> - <enum>Qt::ToolButtonTextBesideIcon</enum> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="tool_goToPlayer"> - <property name="statusTip"> - <string>Enqueue selection in multimedia player</string> - </property> - <property name="text"> - <string>Play</string> - </property> - <property name="iconSize"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - <property name="toolButtonStyle"> - <enum>Qt::ToolButtonTextBesideIcon</enum> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QLabel" name="label_status"> - <property name="text"> - <string notr="true">Status</string> - </property> - <property name="wordWrap"> - <bool>false</bool> - </property> - </widget> - </item> - </layout> - </item> - <item row="2" column="1"> - <layout class="QVBoxLayout" name="browser_layout"> - <property name="spacing"> - <number>1</number> - </property> - <item> - <widget class="QFrame" name="group_snaps"> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <property name="leftMargin"> - <number>1</number> - </property> - <property name="topMargin"> - <number>1</number> - </property> - <property name="rightMargin"> - <number>1</number> - </property> - <property name="bottomMargin"> - <number>1</number> - </property> - <item> - <widget class="QToolButton" name="tool_snap"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="styleSheet"> - <string notr="true">padding-right: 5px;</string> - </property> - <property name="text"> - <string notr="true"/> - </property> - <property name="popupMode"> - <enum>QToolButton::InstantPopup</enum> - </property> - <property name="toolButtonStyle"> - <enum>Qt::ToolButtonTextOnly</enum> - </property> - </widget> - </item> - <item> - <widget class="QSlider" name="slider_snap"> - <property name="minimum"> - <number>1</number> - </property> - <property name="value"> - <number>1</number> - </property> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="invertedAppearance"> - <bool>false</bool> - </property> - <property name="invertedControls"> - <bool>false</bool> - </property> - <property name="tickPosition"> - <enum>QSlider::TicksAbove</enum> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="tool_snap_older"> - <property name="text"> - <string notr="true">...</string> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="tool_snap_newer"> - <property name="text"> - <string notr="true">...</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </item> - <item row="2" column="0"> - <widget class="QFrame" name="group_actions"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QToolButton" name="tool_act_run"> - <property name="toolTip"> - <string>Open item</string> - </property> - <property name="statusTip"> - <string>Open item</string> - </property> - <property name="text"> - <string notr="true"/> - </property> - <property name="iconSize"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - <property name="toolButtonStyle"> - <enum>Qt::ToolButtonIconOnly</enum> - </property> - <property name="autoRaise"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="tool_act_runwith"> - <property name="toolTip"> - <string>Open item (select application)</string> - </property> - <property name="statusTip"> - <string>Open item (select application)</string> - </property> - <property name="text"> - <string notr="true"/> - </property> - <property name="iconSize"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - <property name="autoRaise"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="Line" name="line_5"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="tool_act_fav"> - <property name="toolTip"> - <string>Add item to personal favorites</string> - </property> - <property name="statusTip"> - <string>Add item to personal favorites</string> - </property> - <property name="text"> - <string notr="true"/> - </property> - <property name="iconSize"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - <property name="autoRaise"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="tool_act_rename"> - <property name="toolTip"> - <string>Rename item</string> - </property> - <property name="statusTip"> - <string>Rename item</string> - </property> - <property name="text"> - <string notr="true"/> - </property> - <property name="iconSize"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - <property name="autoRaise"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="Line" name="line_7"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="tool_act_cut"> - <property name="toolTip"> - <string>Cut items</string> - </property> - <property name="statusTip"> - <string>Cut items (add to the clipboard)</string> - </property> - <property name="text"> - <string notr="true"/> - </property> - <property name="iconSize"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - <property name="autoRaise"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="tool_act_copy"> - <property name="toolTip"> - <string>Copy items</string> - </property> - <property name="statusTip"> - <string>Copy items to the clipboard</string> - </property> - <property name="text"> - <string/> - </property> - <property name="iconSize"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - <property name="autoRaise"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="tool_act_paste"> - <property name="toolTip"> - <string>Paste items from clipboard</string> - </property> - <property name="statusTip"> - <string>Paste items from clipboard</string> - </property> - <property name="text"> - <string notr="true"/> - </property> - <property name="iconSize"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - <property name="autoRaise"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="Line" name="line_6"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="tool_act_rm"> - <property name="toolTip"> - <string>Delete Items</string> - </property> - <property name="statusTip"> - <string>Delete Items</string> - </property> - <property name="text"> - <string/> - </property> - <property name="iconSize"> - <size> - <width>20</width> - <height>20</height> - </size> - </property> - <property name="autoRaise"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </item> - </layout> - <action name="actionBack"> - <property name="text"> - <string notr="true">Back</string> - </property> - <property name="iconText"> - <string>Back</string> - </property> - <property name="toolTip"> - <string>Go back to previous directory</string> - </property> - <property name="statusTip"> - <string>Go back to previous directory</string> - </property> - </action> - <action name="actionUp"> - <property name="text"> - <string notr="true">Up</string> - </property> - <property name="iconText"> - <string>Up</string> - </property> - <property name="toolTip"> - <string>Go to parent directory</string> - </property> - <property name="statusTip"> - <string>Go to parent directory</string> - </property> - </action> - <action name="actionHome"> - <property name="text"> - <string notr="true">Home</string> - </property> - <property name="iconText"> - <string>Home</string> - </property> - <property name="toolTip"> - <string>Go to home directory</string> - </property> - <property name="statusTip"> - <string>Go to home directory</string> - </property> - </action> - <action name="actionStopLoad"> - <property name="text"> - <string notr="true"/> - </property> - <property name="statusTip"> - <string>Stop loading the directory</string> - </property> - </action> - <action name="actionClose_Browser"> - <property name="text"> - <string notr="true">Close Browser</string> - </property> - <property name="iconText"> - <string notr="true">Close Browser</string> - </property> - <property name="toolTip"> - <string>Close this browser</string> - </property> - <property name="statusTip"> - <string>Close this browser</string> - </property> - </action> - </widget> - <resources/> - <connections/> -</ui> diff --git a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.cpp b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.cpp new file mode 100644 index 00000000..48ad6aa5 --- /dev/null +++ b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.cpp @@ -0,0 +1,734 @@ +//=========================================== +// Lumina-DE source code +// Copyright (c) 2015, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include "DirWidget2.h" +#include "ui_DirWidget2.h" + +#include <QMessageBox> +#include <QCursor> +#include <QClipboard> +#include <QMimeData> +#include <QTimer> +#include <QInputDialog> +#include <QScrollBar> +#include <QSettings> +#include <QtConcurrent/QtConcurrentRun> + +#include <LuminaOS.h> +#include <LuminaXDG.h> +#include <LUtils.h> + +#include "../ScrollDialog.h" + +#define DEBUG 0 + +DirWidget::DirWidget(QString objID, QWidget *parent) : QWidget(parent), ui(new Ui::DirWidget){ + ui->setupUi(this); //load the designer file + ID = objID; + //Assemble the toolbar for the widget + toolbar = new QToolBar(this); + toolbar->setContextMenuPolicy(Qt::CustomContextMenu); + toolbar->setFloatable(false); + toolbar->setMovable(false); + toolbar->setOrientation(Qt::Horizontal); + toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly); + //toolbar->setIconSize(QSize(32,32)); + ui->toolbar_layout->addWidget(toolbar); + // - Add the buttons to the toolbar + toolbar->addAction(ui->actionBack); + toolbar->addAction(ui->actionUp); + toolbar->addAction(ui->actionHome); + line_dir = new QLineEdit(this); + toolbar->addWidget(line_dir); + connect(line_dir, SIGNAL(returnPressed()), this, SLOT(dir_changed()) ); + toolbar->addAction(ui->actionSingleColumn); + ui->actionSingleColumn->setChecked(true); + toolbar->addAction(ui->actionDualColumn); + toolbar->addAction(ui->actionMenu); + //Add the browser widgets + RCBW = 0; //right column browser is unavailable initially + BW = new BrowserWidget("", this); + ui->browser_layout->addWidget(BW); + connect(BW, SIGNAL(dirChange(QString)), this, SLOT(currentDirectoryChanged()) ); + connect(BW, SIGNAL(itemsActivated()), this, SLOT(runFiles()) ); + connect(BW, SIGNAL(DataDropped(QString, QStringList)), this, SIGNAL(PasteFiles(QString, QStringList)) ); + connect(BW, SIGNAL(contextMenuRequested()), this, SLOT(OpenContextMenu()) ); + connect(BW, SIGNAL(updateDirectoryStatus(QString)), this, SLOT(dirStatusChanged(QString)) ); + connect(BW, SIGNAL(hasFocus(QString)), this, SLOT(setCurrentBrowser(QString)) ); + //Now update the rest of the UI + canmodify = false; //initial value + contextMenu = new QMenu(this); + cNewMenu = cOpenMenu = cFModMenu = cFViewMenu = 0; //not created yet + connect(contextMenu, SIGNAL(aboutToShow()), this, SLOT(UpdateContextMenu()) ); + + UpdateIcons(); + UpdateText(); + createShortcuts(); + createMenus(); +} + +DirWidget::~DirWidget(){ + //stopload = true; //just in case another thread is still loading/running +} + +void DirWidget::setFocusLineDir() { + line_dir->setFocus(); + line_dir->selectAll(); +} + +void DirWidget::cleanup(){ + //stopload = true; //just in case another thread is still loading/running + //if(thumbThread.isRunning()){ thumbThread.waitForFinished(); } //this will stop really quickly with the flag set +} + +void DirWidget::ChangeDir(QString dirpath){ + //stopload = true; //just in case it is still loading + //emit LoadDirectory(ID, dirpath); + //qDebug() << "ChangeDir:" << dirpath; + currentBrowser()->changeDirectory(dirpath); +} + +void DirWidget::setDirCompleter(QCompleter *comp){ + //line_dir->setCompleter(comp); +} + +QString DirWidget::id(){ + return ID; +} + +QString DirWidget::currentDir(){ + return currentBrowser()->currentDirectory(); +} + +void DirWidget::setShowDetails(bool show){ + BW->showDetails(show); + if(RCBW!=0){ RCBW->showDetails(show); } +} + +void DirWidget::showHidden(bool show){ + BW->showHiddenFiles(show); + if(RCBW!=0){ RCBW->showHiddenFiles(show); } +} + +void DirWidget::setThumbnailSize(int px){ + BW->setThumbnailSize(px); + if(RCBW!=0){ RCBW->setThumbnailSize(px); } + ui->tool_zoom_in->setEnabled(px < 256); //upper limit on image sizes + ui->tool_zoom_out->setEnabled(px >16); //lower limit on image sizes +} + +// ================ +// PUBLIC SLOTS +// ================ + +void DirWidget::LoadSnaps(QString basedir, QStringList snaps){ + //Save these value internally for use later + //qDebug() << "ZFS Snapshots available:" << basedir << snaps; + snapbasedir = basedir; + snapshots = snaps; + //if(!snapbasedir.isEmpty()){ watcher->addPath(snapbasedir); } //add this to the watcher in case snapshots get created/removed + //Now update the UI as necessary + if(ui->tool_snap->menu()==0){ + ui->tool_snap->setMenu(new QMenu(this)); + connect(ui->tool_snap->menu(), SIGNAL(triggered(QAction*)), this, SLOT(direct_snap_selected(QAction*)) ); + } + ui->tool_snap->menu()->clear(); + for(int i=0; i<snapshots.length(); i++){ + QAction *tmp = ui->tool_snap->menu()->addAction(snapshots[i]); + tmp->setWhatsThis(snapshots[i]); + } + ui->slider_snap->setRange(0, snaps.length()); + if(currentBrowser()->currentDirectory().contains(ZSNAPDIR)){ + //The user was already within a snapshot - figure out which one and set the slider appropriately + int index = snaps.indexOf( currentBrowser()->currentDirectory().section(ZSNAPDIR,1,1).section("/",0,0) ); + if(index < 0){ index = snaps.length(); } //unknown - load the system (should never happen) + ui->slider_snap->setValue(index); + }else{ + ui->slider_snap->setValue(snaps.length()); //last item (normal system) + } + on_slider_snap_valueChanged(); + QApplication::processEvents(); //let the slider changed signal get thrown away before we re-enable the widget + ui->group_snaps->setEnabled(!snaps.isEmpty()); + ui->group_snaps->setVisible(!snaps.isEmpty()); + ui->tool_snap_newer->setEnabled(ui->slider_snap->value() < ui->slider_snap->maximum()); + ui->tool_snap_older->setEnabled(ui->slider_snap->value() > ui->slider_snap->minimum()); +} + +void DirWidget::refresh(){ + currentBrowser()->changeDirectory(""); //refresh current dir +} + +//Theme change functions +void DirWidget::UpdateIcons(){ + //Snapshot buttons + ui->tool_snap_newer->setIcon(LXDG::findIcon("go-next-view","") ); + ui->tool_snap_older->setIcon(LXDG::findIcon("go-previous-view","") ); + + //ToolBar Buttons + ui->actionBack->setIcon( LXDG::findIcon("go-previous","") ); + ui->actionUp->setIcon( LXDG::findIcon("go-up","") ); + ui->actionHome->setIcon( LXDG::findIcon("go-home","") ); + ui->actionMenu->setIcon( LXDG::findIcon("format-justify-fill","format-list-unordered") ); + ui->actionSingleColumn->setIcon(LXDG::findIcon("view-right-close","view-close") ); + ui->actionDualColumn->setIcon(LXDG::findIcon("view-right-new","view-split-left-right") ); + + ui->tool_zoom_in->setIcon(LXDG::findIcon("zoom-in","")); + ui->tool_zoom_out->setIcon(LXDG::findIcon("zoom-out","")); + +} + +void DirWidget::UpdateText(){ + ui->retranslateUi(this); + BW->retranslate(); + if(RCBW!=0){ RCBW->retranslate(); } +} + +// ================= +// PRIVATE +// ================= +void DirWidget::createShortcuts(){ +kZoomIn= new QShortcut(QKeySequence(QKeySequence::ZoomIn),this); +kZoomOut= new QShortcut(QKeySequence(QKeySequence::ZoomOut),this); +kNewFile= new QShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_F),this); +kNewDir= new QShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_N),this); +kNewXDG= new QShortcut(QKeySequence(Qt::CTRL+Qt::Key_G),this); +kCut= new QShortcut(QKeySequence(QKeySequence::Cut),this); +kCopy= new QShortcut(QKeySequence(QKeySequence::Copy),this); +kPaste= new QShortcut(QKeySequence(QKeySequence::Paste),this); +kRename= new QShortcut(QKeySequence(Qt::Key_F2),this); +kFav= new QShortcut(QKeySequence(Qt::Key_F3),this); +kDel= new QShortcut(QKeySequence(QKeySequence::Delete),this); +kOpSS= new QShortcut(QKeySequence(Qt::Key_F6),this); +kOpMM= new QShortcut(QKeySequence(Qt::Key_F7),this); +kOpTerm = new QShortcut(QKeySequence(Qt::Key_F1),this); + +connect(kZoomIn, SIGNAL(activated()), this, SLOT(on_tool_zoom_in_clicked()) ); +connect(kZoomOut, SIGNAL(activated()), this, SLOT(on_tool_zoom_out_clicked()) ); +connect(kNewFile, SIGNAL(activated()), this, SLOT(createNewFile()) ); +connect(kNewDir, SIGNAL(activated()), this, SLOT(createNewDir()) ); +connect(kNewXDG, SIGNAL(activated()), this, SLOT(createNewXDGEntry()) ); +connect(kCut, SIGNAL(activated()), this, SLOT(cutFiles()) ); +connect(kCopy, SIGNAL(activated()), this, SLOT(copyFiles()) ); +connect(kPaste, SIGNAL(activated()), this, SLOT(pasteFiles()) ); +connect(kRename, SIGNAL(activated()), this, SLOT(renameFiles()) ); +connect(kFav, SIGNAL(activated()), this, SLOT(favoriteFiles()) ); +connect(kDel, SIGNAL(activated()), this, SLOT(removeFiles()) ); +connect(kOpSS, SIGNAL(activated()), this, SLOT(openInSlideshow()) ); +connect(kOpMM, SIGNAL(activated()), this, SLOT(openMultimedia()) ); +connect(kOpTerm, SIGNAL(activated()), this, SLOT(openTerminal()) ); + +} + +void DirWidget::createMenus(){ + //Note: contextMenu already created - this is just for the sub-items + if(cNewMenu==0){ cNewMenu = new QMenu(this); } + else{ cNewMenu->clear(); } + cNewMenu->setTitle(tr("Create...") ); + cNewMenu->setIcon( LXDG::findIcon("list-add","") ); + cNewMenu->addAction(LXDG::findIcon("document-new",""), tr("File"), this, SLOT(createNewFile()), kNewFile->key() ); + cNewMenu->addAction(LXDG::findIcon("folder-new",""), tr("Directory"), this, SLOT(createNewDir()), kNewDir->key() ); + if(LUtils::isValidBinary("lumina-fileinfo")){ cNewMenu->addAction(LXDG::findIcon("system-run",""), tr("Application Launcher"), this, SLOT(createNewXDGEntry()), kNewXDG->key() ); } + + if(cOpenMenu==0){ cOpenMenu = new QMenu(this); } + else{ cOpenMenu->clear(); } + cOpenMenu->setTitle(tr("Launch...")); + cOpenMenu->setIcon( LXDG::findIcon("quickopen","") ); + cOpenMenu->addAction(LXDG::findIcon("utilities-terminal",""), tr("Terminal"), this, SLOT(openTerminal()), kOpTerm->key()); + cOpenMenu->addAction(LXDG::findIcon("view-preview",""), tr("SlideShow"), this, SLOT(openInSlideshow()), kOpSS->key()); + cOpenMenu->addAction(LXDG::findIcon("view-media-lyrics","media-playback-start"), tr("Multimedia Player"), this, SLOT(openMultimedia()), kOpMM->key()); + + if(cFModMenu==0){ cFModMenu = new QMenu(this); } + else{ cFModMenu->clear(); } + cFModMenu->setTitle(tr("Modify Files...")); + cFModMenu->setIcon( LXDG::findIcon("document-edit","") ); + cFModMenu->addAction(LXDG::findIcon("edit-cut",""), tr("Cut Selection"), this, SLOT(cutFiles()), kCut->key() ); + cFModMenu->addAction(LXDG::findIcon("edit-copy",""), tr("Copy Selection"), this, SLOT(copyFiles()), kCopy->key() ); + cFModMenu->addSeparator(); + cFModMenu->addAction(LXDG::findIcon("edit-rename",""), tr("Rename..."), this, SLOT(renameFiles()), kRename->key() ); + cFModMenu->addSeparator(); + cFModMenu->addAction(LXDG::findIcon("edit-delete",""), tr("Delete Selection"), this, SLOT(removeFiles()), kDel->key() ); + + if(cFViewMenu==0){ cFViewMenu = new QMenu(this); } + else{ cFViewMenu->clear(); } + cFViewMenu->setTitle(tr("View Files...")); + cFViewMenu->setIcon( LXDG::findIcon("document-preview","") ); + cFViewMenu->addAction(LXDG::findIcon("document-encrypted",""), tr("Checksums"), this, SLOT(fileCheckSums()) ); + if(LUtils::isValidBinary("lumina-fileinfo")){ + cFViewMenu->addAction(LXDG::findIcon("edit-find-replace",""), tr("Properties"), this, SLOT(fileProperties()) ); + } + +} + +BrowserWidget* DirWidget::currentBrowser(){ + if(cBID.isEmpty() || RCBW==0){ return BW; } + else{ return RCBW; } +} + +QStringList DirWidget::currentDirFiles(){ + return currentBrowser()->currentItems(-1); //files only +} +// ================= +// PRIVATE SLOTS +// ================= + +//UI BUTTONS +void DirWidget::on_tool_zoom_in_clicked(){ + int size = BW->thumbnailSize(); + size += 16; + setThumbnailSize(size); + //Now Save the size value as the default for next time + QSettings SET("lumina-desktop","lumina-fm"); + SET.setValue("iconsize", size); +} + +void DirWidget::on_tool_zoom_out_clicked(){ + int size = BW->thumbnailSize(); + if(size <= 16){ return; } + size -= 16; + setThumbnailSize(size); + //Now Save the size value as the default for next time + QSettings SET("lumina-desktop","lumina-fm"); + SET.setValue("iconsize", size); +} + +// -- Top Snapshot Buttons +void DirWidget::on_tool_snap_newer_clicked(){ + ui->slider_snap->setValue( ui->slider_snap->value()+1 ); +} + +void DirWidget::on_tool_snap_older_clicked(){ + ui->slider_snap->setValue( ui->slider_snap->value()-1 ); +} + +void DirWidget::on_slider_snap_valueChanged(int val){ + bool labelsonly = false; + if(val==-1){ val = ui->slider_snap->value(); labelsonly=true; } + //Update the snapshot interface + ui->tool_snap_newer->setEnabled(val < ui->slider_snap->maximum()); + ui->tool_snap_older->setEnabled(val > ui->slider_snap->minimum()); + if(val >= snapshots.length() || val < 0){ + ui->tool_snap->setText(tr("Current")); + }else if(QFile::exists(snapbasedir+snapshots[val])){ + ui->tool_snap->setText( QFileInfo(snapbasedir+snapshots[val]).lastModified().toString(Qt::DefaultLocaleShortDate) ); + } + //Exit if a non-interactive snapshot change + if(!ui->group_snaps->isEnabled() || labelsonly){ return; } //internal change - do not try to change the actual info + //Determine which snapshot is now selected + QString dir; + if(DEBUG){ qDebug() << "Changing snapshot:" << currentBrowser()->currentDirectory() << val << snapbasedir; } + //stopload = true; //stop any currently-loading procedures + if(val >= snapshots.length() || val < 0){ //active system selected + if(DEBUG){ qDebug() << " - Load Active system:" << normalbasedir; } + dir = normalbasedir; + }else{ + dir = snapbasedir+snapshots[val]+"/"; + if(!QFile::exists(dir)){ + //This snapshot must have been removed in the background by pruning tools + // move to a newer snapshot or the current base dir as necessary + qDebug() << "Snapshot no longer available:" << dir; + qDebug() << " - Reloading available snapshots"; + emit findSnaps(ID, normalbasedir); + return; + } + //Need to figure out the relative path within the snapshot + snaprelpath = normalbasedir.section(snapbasedir.section(ZSNAPDIR,0,0), 1,1000); + if(DEBUG){ qDebug() << " - new snapshot-relative path:" << snaprelpath; } + dir.append(snaprelpath); + dir.replace("//","/"); //just in case any duplicate slashes from all the split/combining + if(DEBUG){ qDebug() << " - Load Snapshot:" << dir; } + } + //Make sure this directory exists, and back up as necessary + if(dir.isEmpty()){ return; } + //Load the newly selected snapshot + currentBrowser()->changeDirectory(dir); +} + +void DirWidget::direct_snap_selected(QAction *act){ + QString snap = act->whatsThis(); + int val = snapshots.indexOf(snap); + if(val<0){ return; } + else{ ui->slider_snap->setValue(val); } +} + +//Top Toolbar buttons +void DirWidget::on_actionBack_triggered(){ + QStringList history = currentBrowser()->history(); + if(history.length()<2){ return; } //cannot do anything + QString dir = history.takeLast(); + //qDebug() << "Go Back:" << dir << normalbasedir << history; + if(dir == normalbasedir){ + dir = history.takeLast(); + } + history << dir; //make sure the current dir is always last in the history + currentBrowser()->changeDirectory(dir); + currentBrowser()->setHistory(history); //re-write the history to account for going backwards + ui->actionBack->setEnabled(history.length()>1); +} + +void DirWidget::on_actionUp_triggered(){ + QString dir = currentBrowser()->currentDirectory().section("/",0,-2); + if(dir.isEmpty()) + dir = "/"; + //Quick check to ensure the directory exists + while(!QFile::exists(dir) && !dir.isEmpty()){ + dir = dir.section("/",0,-2); //back up one additional dir + } + currentBrowser()->changeDirectory(dir); +} + +void DirWidget::on_actionHome_triggered(){ + currentBrowser()->changeDirectory(QDir::homePath()); +} + +void DirWidget::dir_changed(){ + QString dir = line_dir->text().simplified(); + //Run the dir through the user-input checks + dir = LUtils::PathToAbsolute(dir); + //qDebug() << "Dir Changed:" << dir; + //Quick check to ensure the directory exists + while(!QFile::exists(dir) && !dir.isEmpty()){ + dir = dir.section("/",0,-2); //back up one additional dir + } + //qDebug() << " - Now Dir:" << dir; + currentBrowser()->changeDirectory(dir); + //emit LoadDirectory(ID, dir); +} + + +void DirWidget::on_actionSingleColumn_triggered(bool checked){ + if(!checked){ return; } + ui->actionDualColumn->setChecked(false); + if(RCBW==0){ return; } //nothing to do + ui->browser_layout->removeWidget(RCBW); + RCBW->deleteLater(); + RCBW = 0; + setCurrentBrowser(""); //reset back to the remaining browser +} + +void DirWidget::on_actionDualColumn_triggered(bool checked){ + if(!checked){ return; } + ui->actionSingleColumn->setChecked(false); + if(RCBW!=0){ return; } //nothing to do + RCBW = new BrowserWidget("rc", this); + ui->browser_layout->addWidget(RCBW); + connect(RCBW, SIGNAL(dirChange(QString)), this, SLOT(currentDirectoryChanged()) ); + connect(RCBW, SIGNAL(itemsActivated()), this, SLOT(runFiles()) ); + connect(RCBW, SIGNAL(DataDropped(QString, QStringList)), this, SIGNAL(PasteFiles(QString, QStringList)) ); + connect(RCBW, SIGNAL(contextMenuRequested()), this, SLOT(OpenContextMenu()) ); + connect(RCBW, SIGNAL(updateDirectoryStatus(QString)), this, SLOT(dirStatusChanged(QString)) ); + connect(RCBW, SIGNAL(hasFocus(QString)), this, SLOT(setCurrentBrowser(QString)) ); + //Now make sure it has all the same settings as the main browser + setCurrentBrowser("rc"); + RCBW->showDetails(BW->hasDetails()); + RCBW->showHiddenFiles( BW->hasHiddenFiles()); + RCBW->setThumbnailSize( BW->thumbnailSize()); + RCBW->changeDirectory( BW->currentDirectory()); +} + +void DirWidget::on_actionMenu_triggered(){ + OpenContextMenu(); +} + + +// - Other Actions without a specific button on the side +void DirWidget::fileCheckSums(){ + QStringList files = currentBrowser()->currentSelection(); + if(files.isEmpty()){ return; } + qDebug() << "Run Checksums:" << files; + QStringList info = LOS::Checksums(files); + qDebug() << " - Info:" << info; + if(info.isEmpty() || (info.length() != files.length()) ){ return; } + for(int i=0; i<info.length(); i++){ + info[i] = QString("%2\n\t(%1)").arg(files[i].section("/",-1), info[i]); + } + ScrollDialog dlg(this); + dlg.setWindowTitle( tr("File Checksums:") ); + dlg.setWindowIcon( LXDG::findIcon("document-encrypted","") ); + dlg.setText(info.join("\n")); + dlg.exec(); +} + +void DirWidget::fileProperties(){ + QStringList sel = currentBrowser()->currentSelection(); + //qDebug() << "Open File properties:" << sel; + if(sel.isEmpty()){ return; } + if(!LUtils::isValidBinary("lumina-fileinfo")){ + //It should never get to this point due to checks earlier - but just in case... + QMessageBox::warning(this, tr("Missing Utility"), tr("The \"lumina-fileinfo\" utility could not be found on the system. Please install it first.") ); + return; + } + for(int i=0; i<sel.length(); i++){ + QProcess::startDetached("lumina-fileinfo \""+sel[i]+"\""); //use absolute paths + } +} + +void DirWidget::openTerminal(){ + emit LaunchTerminal(currentBrowser()->currentDirectory()); +} + +//Browser Functions +void DirWidget::OpenContextMenu(){ + //Now open the menu at the current cursor location + contextMenu->popup(QCursor::pos()); +} + +void DirWidget::UpdateContextMenu(){ + //First generate the context menu based on the selection + //qDebug() << "Update context menu"; + QStringList sel = currentBrowser()->currentSelection(); + contextMenu->clear(); + + if(!sel.isEmpty()){ + contextMenu->addAction(LXDG::findIcon("run-build-file",""), tr("Open"), this, SLOT(runFiles()) ); + contextMenu->addAction(LXDG::findIcon("run-build-configure",""), tr("Open With..."), this, SLOT(runWithFiles()) ); + } + contextMenu->addSection(LXDG::findIcon("unknown",""), tr("File Operations")); + contextMenu->addMenu(cFModMenu); + cFModMenu->setEnabled(!sel.isEmpty() && canmodify); + contextMenu->addMenu(cFViewMenu); + cFViewMenu->setEnabled(!sel.isEmpty()); + contextMenu->addAction(LXDG::findIcon("edit-paste",""), tr("Paste"), this, SLOT(pasteFiles()), QKeySequence(Qt::CTRL+Qt::Key_V) )->setEnabled(QApplication::clipboard()->mimeData()->hasFormat("x-special/lumina-copied-files") && canmodify); + //Now add the general selection options + contextMenu->addSection(LXDG::findIcon("folder","inode/directory"), tr("Directory Operations")); + if(canmodify){ + contextMenu->addMenu(cNewMenu); + } + contextMenu->addMenu(cOpenMenu); +} + +void DirWidget::currentDirectoryChanged(bool widgetonly){ + QString cur = currentBrowser()->currentDirectory(); + QFileInfo info(cur); + canmodify = info.isWritable(); + if(widgetonly){ ui->label_status->setText(currentBrowser()->status()); } + else if( !currentBrowser()->isEnabled() ){ ui->label_status->setText(tr("Loading...")); } + //qDebug() << "Start search for snapshots"; + if(!cur.contains("/.zfs/snapshot") ){ + normalbasedir = cur; + ui->group_snaps->setVisible(false); + emit findSnaps(ID, cur); + qDebug() << "Changed to directory:" << cur; + }else{ + //Re-assemble the normalbasedir variable (in case moving around within a snapshot) + normalbasedir = cur; + normalbasedir.replace( QRegExp("\\/\\.zfs\\/snapshot/([^/]+)\\/"), "/" ); + qDebug() << "Changed to snapshot:" << cur << normalbasedir; + } + ui->actionBack->setEnabled( currentBrowser()->history().length()>1 ); + line_dir->setText(normalbasedir); + emit TabNameChanged(ID, normalbasedir.section("/",-1)); +} + +void DirWidget::dirStatusChanged(QString stat){ + if(!canmodify){ stat.prepend(tr("(Limited Access) ")); } + ui->label_status->setText(stat); +} + +void DirWidget::setCurrentBrowser(QString id){ + //qDebug() << "Set Current Browser:" << id; + if(id==cBID){ return; } //no change + cBID = id; + currentDirectoryChanged(true); //update all the averarching widget elements (widget only) + //Now adjust the frame/highlighting around the "active" browser + if(RCBW==0){ BW->setShowActive(true); } + else{ + BW->setShowActive( cBID.isEmpty() ); + RCBW->setShowActive( !cBID.isEmpty() ); + } +} + +//Context Menu Functions +void DirWidget::createNewFile(){ + if(!canmodify){ return; } //cannot create anything here + //Prompt for the new filename + bool ok = false; + QString newdocument = QInputDialog::getText(this, tr("New Document"), tr("Name:"), QLineEdit::Normal, "", \ + &ok, 0, Qt::ImhFormattedNumbersOnly | Qt::ImhUppercaseOnly | Qt::ImhLowercaseOnly); + if(!ok || newdocument.isEmpty()){ return; } + //Create the empty file + QString full = currentBrowser()->currentDirectory(); + if(!full.endsWith("/")){ full.append("/"); } + //verify the new file does not already exist + if(QFile::exists(full+newdocument)){ + QMessageBox::warning(this, tr("Invalid Name"), tr("A file or directory with that name already exists! Please pick a different name.")); + QTimer::singleShot(0,this, SLOT(createNewFile()) ); //repeat this function + return; + } + QFile file(full+newdocument); + if(file.open(QIODevice::ReadWrite)){ + //If successfully opened, it has created a blank file + file.close(); + }else{ + QMessageBox::warning(this, tr("Error Creating Document"), tr("The document could not be created. Please ensure that you have the proper permissions.")); + } +} + +void DirWidget::createNewDir(){ + if(!canmodify){ return; } //cannot create anything here + //Prompt for the new dir name + bool ok = false; + QString newdir = QInputDialog::getText(this, tr("New Directory"), tr("Name:"), QLineEdit::Normal, "", \ + &ok, 0, Qt::ImhFormattedNumbersOnly | Qt::ImhUppercaseOnly | Qt::ImhLowercaseOnly); + if(!ok || newdir.isEmpty()){ return; } + //Now create the new dir + QString full = currentBrowser()->currentDirectory(); + if(!full.endsWith("/")){ full.append("/"); } + QDir dir(full); //open the current dir + full.append(newdir); //append the new name to the current dir + //Verify that the new dir does not already exist + if(dir.exists(full)){ + QMessageBox::warning(this, tr("Invalid Name"), tr("A file or directory with that name already exists! Please pick a different name.")); + QTimer::singleShot(0,this, SLOT(createNewDir()) ); //repeat this function + }else{ + if(!dir.mkdir(newdir) ){ + 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.")); + } + } +} + +void DirWidget::createNewXDGEntry(){ + if(!canmodify){ return; } //cannot create anything here + //Prompt for the new filename + bool ok = false; + QString newdocument = QInputDialog::getText(this, tr("New Document"), tr("Name:"), QLineEdit::Normal, "", \ + &ok, 0, Qt::ImhFormattedNumbersOnly | Qt::ImhUppercaseOnly | Qt::ImhLowercaseOnly); + if(!ok || newdocument.isEmpty()){ return; } + if(!newdocument.endsWith(".desktop")){ newdocument.append(".desktop"); } + //Create the empty file + QString full = currentBrowser()->currentDirectory(); + if(!full.endsWith("/")){ full.append("/"); } + //Verify the file does not already exist + if(QFile::exists(full+newdocument)){ + QMessageBox::warning(this, tr("Invalid Name"), tr("A file or directory with that name already exists! Please pick a different name.")); + QTimer::singleShot(0,this, SLOT(createNewFile()) ); //repeat this function + return; + } + QProcess::startDetached("lumina-fileinfo -application \""+full+newdocument+"\""); +} + +/*void DirWidget::createNewSymlink{ + +}*/ + +// - Selected FILE operations +void DirWidget::cutFiles(){ + QStringList sel = currentBrowser()->currentSelection(); + if(sel.isEmpty() || !canmodify){ return; } + emit CutFiles(sel); +} + +void DirWidget::copyFiles(){ + QStringList sel = currentBrowser()->currentSelection(); + if(sel.isEmpty()){ return; } + emit CopyFiles(sel); +} + +void DirWidget::pasteFiles(){ + if( !canmodify ){ return; } + emit PasteFiles(currentBrowser()->currentDirectory(), QStringList() ); +} + +void DirWidget::renameFiles(){ + QStringList sel = currentBrowser()->currentSelection(); + if(sel.isEmpty() || !canmodify){ return; } + qDebug() << "Deleting selected Items:" << sel; + emit RenameFiles(sel); +} + +void DirWidget::favoriteFiles(){ + QStringList sel = currentBrowser()->currentSelection(); + if(sel.isEmpty()){ return; } + emit FavoriteFiles(sel); +} + +void DirWidget::removeFiles(){ + QStringList sel = currentBrowser()->currentSelection(); + if(sel.isEmpty() || !canmodify){ return; } + qDebug() << "Deleting selected Items:" << sel; + emit RemoveFiles(sel); +} + +void DirWidget::runFiles(){ + QStringList sel = currentBrowser()->currentSelection(); + if(sel.isEmpty()){ return; } + QStringList dirs; + for(int i=0; i<sel.length(); i++){ + if(QFileInfo(sel[i]).isDir()){ + dirs << sel[i]; + }else{ + QProcess::startDetached("lumina-open \""+sel[i]+"\""); + } + } + if(!dirs.isEmpty()){ + currentBrowser()->changeDirectory( dirs.takeFirst()); //load the first directory in this widget + } + if(!dirs.isEmpty()){ + emit OpenDirectories(dirs); //open the rest of the directories in other tabs + } +} + +void DirWidget::runWithFiles(){ + QStringList sel = currentBrowser()->currentSelection(); + if(sel.isEmpty()){ return; } + QStringList dirs; + for(int i=0; i<sel.length(); i++){ + if(QFileInfo(sel[i]).isDir()){ + dirs << sel[i]; + }else{ + QProcess::startDetached("lumina-open -select \""+sel[i]+"\""); + } + } + if(!dirs.isEmpty()){ + emit OpenDirectories(dirs); //open the rest of the directories in other tabs + } +} + +/*void DirWidget::attachToNewEmail(){ + +}*/ + +// - Context-specific operations +void DirWidget::openInSlideshow(){ + QStringList sel = currentBrowser()->currentSelection(); + if(sel.isEmpty()){ sel = currentDirFiles(); } + //Now turn them all into a list and emit them + LFileInfoList list; + for(int i=0; i<sel.length(); i++){ + if(sel.endsWith(".desktop")){ continue; } //simplification to make sure we don't read any files which are not needed + LFileInfo info(sel[i]); + if( info.isImage() ){ list << info; } //add to the list + } + if(!list.isEmpty()){ emit ViewFiles(list); } +} + +void DirWidget::openMultimedia(){ + QStringList sel = currentBrowser()->currentSelection(); + if(sel.isEmpty()){ sel = currentDirFiles(); } + //Now turn them all into a list and emit them + LFileInfoList list; + for(int i=0; i<sel.length(); i++){ + if(sel.endsWith(".desktop")){ continue; } //simplification to make sure we don't read any files which are not needed + LFileInfo info(sel[i]); + if( info.isAVFile() ){ list << info; } //add to the list + } + if(!list.isEmpty()){ emit PlayFiles(list); } +} + +//==================== +// PROTECTED +//==================== +void DirWidget::mouseReleaseEvent(QMouseEvent *ev){ + static Qt::MouseButtons backmap = Qt::BackButton | Qt::ExtraButton5; + //qDebug() << "Mouse Click:" << ev->button(); + if(backmap.testFlag(ev->button())){ + ev->accept(); + on_actionBack_triggered(); + //}else if(ev->button()==Qt::ForwardButton()){ + //ev->accept(); + }else{ + ev->ignore(); //not handled here + } +} diff --git a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.h b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.h new file mode 100644 index 00000000..38e7a657 --- /dev/null +++ b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.h @@ -0,0 +1,173 @@ +//=========================================== +// Lumina-DE source code +// Copyright (c) 2015, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#ifndef _LUMINA_FM_DIRECTORY_BROWSER_WIDGET_H +#define _LUMINA_FM_DIRECTORY_BROWSER_WIDGET_H + +#include <QList> +#include <QWidget> +#include <QObject> +#include <QMenu> +#include <QToolBar> +#include <QLineEdit> +#include <QShortcut> +#include <QFileSystemWatcher> +#include <QTimer> +#include <QFuture> + +#include "../BrowserWidget.h" + + +#define ZSNAPDIR QString("/.zfs/snapshot/") + +namespace Ui{ + class DirWidget; +}; + +class DirWidget : public QWidget{ + Q_OBJECT +public: + enum DETAILTYPES{ NAME, SIZE, TYPE, DATEMOD, DATECREATE}; + DirWidget(QString objID, QWidget *parent = 0); //needs a unique ID (to distinguish from other DirWidgets) + ~DirWidget(); + + void cleanup(); //called before the browser is closed down + + //Directory Managment + void ChangeDir(QString dirpath); + void setDirCompleter(QCompleter *comp); + + //Information + QString id(); + QString currentDir(); + + //View Settings + void setShowDetails(bool show); + void showHidden(bool show); + void setThumbnailSize(int px); + void setFocusLineDir(); + +public slots: + //void LoadDir(QString dir, LFileInfoList list); + void LoadSnaps(QString basedir, QStringList snaps); + + //Refresh options + void refresh(); //Refresh current directory + + //Theme change functions + void UpdateIcons(); + void UpdateText(); + + +private: + Ui::DirWidget *ui; + BrowserWidget *BW, *RCBW; //Main BrowserWidget and right-column browser widget + QString ID, cBID; //unique ID assigned by the parent, and currently active browser widget + QString normalbasedir, snapbasedir, snaprelpath; //for maintaining directory context while moving between snapshots + QStringList snapshots, needThumbs, tmpSel; + bool canmodify; + + //The Toolbar and associated items + QToolBar *toolbar; + QLineEdit *line_dir; + + //The context menu and associated items + QMenu *contextMenu, *cNewMenu, *cOpenMenu, *cFModMenu, *cFViewMenu; + + //The keyboard shortcuts for context menu items + QShortcut *kZoomIn, *kZoomOut, *kNewFile, *kNewDir, *kNewXDG, *kCut, *kCopy, *kPaste, *kRename, \ + *kFav, *kDel, *kOpSS, *kOpMM, *kOpTerm; + + //Functions for internal use + void createShortcuts(); //on init only + void createMenus(); //on init only + + BrowserWidget* currentBrowser(); + QStringList currentDirFiles(); //all the "files" available within the current dir/browser + +private slots: + //UI BUTTONS/Actions + + // -- Bottom Action Buttons + void on_tool_zoom_in_clicked(); + void on_tool_zoom_out_clicked(); + + // -- Top Snapshot Buttons + void on_tool_snap_newer_clicked(); + void on_tool_snap_older_clicked(); + void on_slider_snap_valueChanged(int val = -1); + void direct_snap_selected(QAction*); + + //Top Toolbar buttons + void on_actionBack_triggered(); + void on_actionUp_triggered(); + void on_actionHome_triggered(); + void dir_changed(); //user manually changed the directory + void on_actionSingleColumn_triggered(bool); + void on_actionDualColumn_triggered(bool); + void on_actionMenu_triggered(); + + // - Other Actions without a specific button on the side + void fileCheckSums(); + void fileProperties(); + void openTerminal(); + + + //Browser Functions + void OpenContextMenu(); + void UpdateContextMenu(); + void currentDirectoryChanged(bool widgetonly = false); + void dirStatusChanged(QString); + void setCurrentBrowser(QString); + + //Context Menu Functions + // - DIRECTORY operations + void createNewFile(); + void createNewDir(); + void createNewXDGEntry(); + //void createNewSymlink(); + + // - Selected FILE operations + void cutFiles(); + void copyFiles(); + void pasteFiles(); + void renameFiles(); + void favoriteFiles(); + void removeFiles(); + void runFiles(); + void runWithFiles(); + //void attachToNewEmail(); + + // - Context-specific operations + void openInSlideshow(); + void openMultimedia(); + +signals: + //Directory loading/finding signals + void OpenDirectories(QStringList); //Directories to open in other tabs/columns + void findSnaps(QString, QString); //ID, dirpath (Request snapshot information for a directory) + void CloseBrowser(QString); //ID (Request that this browser be closed) + + //External App/Widget launching + void PlayFiles(LFileInfoList); //open in multimedia player + void ViewFiles(LFileInfoList); //open in slideshow + void LaunchTerminal(QString); //dirpath + + //System Interactions + void CutFiles(QStringList); //file selection + void CopyFiles(QStringList); //file selection + void PasteFiles(QString, QStringList); //current dir + void FavoriteFiles(QStringList); //file selection + void RenameFiles(QStringList); //file selection + void RemoveFiles(QStringList); //file selection + void TabNameChanged(QString, QString); //objID, new tab name + +protected: + void mouseReleaseEvent(QMouseEvent *); + +}; + +#endif diff --git a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.ui b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.ui new file mode 100644 index 00000000..29660ad4 --- /dev/null +++ b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.ui @@ -0,0 +1,249 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>DirWidget</class> + <widget class="QWidget" name="DirWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>350</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>350</width> + <height>0</height> + </size> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0" columnstretch="0,1"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <property name="horizontalSpacing"> + <number>1</number> + </property> + <property name="verticalSpacing"> + <number>2</number> + </property> + <item row="0" column="0" rowspan="2" colspan="2"> + <layout class="QHBoxLayout" name="toolbar_layout"/> + </item> + <item row="2" column="1"> + <layout class="QVBoxLayout" name="browser_layout_main"> + <property name="spacing"> + <number>1</number> + </property> + <item> + <widget class="QFrame" name="group_snaps"> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <property name="leftMargin"> + <number>1</number> + </property> + <property name="topMargin"> + <number>1</number> + </property> + <property name="rightMargin"> + <number>1</number> + </property> + <property name="bottomMargin"> + <number>1</number> + </property> + <item> + <widget class="QToolButton" name="tool_snap"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="styleSheet"> + <string notr="true">padding-right: 5px;</string> + </property> + <property name="text"> + <string notr="true"/> + </property> + <property name="popupMode"> + <enum>QToolButton::InstantPopup</enum> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextOnly</enum> + </property> + </widget> + </item> + <item> + <widget class="QSlider" name="slider_snap"> + <property name="minimum"> + <number>1</number> + </property> + <property name="value"> + <number>1</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="invertedAppearance"> + <bool>false</bool> + </property> + <property name="invertedControls"> + <bool>false</bool> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksAbove</enum> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="tool_snap_older"> + <property name="text"> + <string notr="true">...</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="tool_snap_newer"> + <property name="text"> + <string notr="true">...</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="browser_layout"/> + </item> + </layout> + </item> + <item row="3" column="0" colspan="2"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label_status"> + <property name="text"> + <string notr="true">Status</string> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="tool_zoom_in"> + <property name="toolTip"> + <string>Increase Icon Sizes</string> + </property> + <property name="text"> + <string notr="true">ZoomIn</string> + </property> + <property name="popupMode"> + <enum>QToolButton::InstantPopup</enum> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="tool_zoom_out"> + <property name="toolTip"> + <string>Decrease Icon Sizes</string> + </property> + <property name="text"> + <string notr="true">ZoomOut</string> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + <action name="actionBack"> + <property name="text"> + <string notr="true">Back</string> + </property> + <property name="iconText"> + <string>Back</string> + </property> + <property name="toolTip"> + <string>Go back to previous directory</string> + </property> + <property name="statusTip"> + <string>Go back to previous directory</string> + </property> + </action> + <action name="actionUp"> + <property name="text"> + <string notr="true">Up</string> + </property> + <property name="iconText"> + <string>Up</string> + </property> + <property name="toolTip"> + <string>Go to parent directory</string> + </property> + <property name="statusTip"> + <string>Go to parent directory</string> + </property> + </action> + <action name="actionHome"> + <property name="text"> + <string notr="true">Home</string> + </property> + <property name="iconText"> + <string>Home</string> + </property> + <property name="toolTip"> + <string>Go to home directory</string> + </property> + <property name="statusTip"> + <string>Go to home directory</string> + </property> + </action> + <action name="actionMenu"> + <property name="text"> + <string>Menu</string> + </property> + <property name="toolTip"> + <string>Select Action</string> + </property> + </action> + <action name="actionSingleColumn"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>SingleColumn</string> + </property> + <property name="toolTip"> + <string>Single column view</string> + </property> + </action> + <action name="actionDualColumn"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Dual Column</string> + </property> + <property name="toolTip"> + <string>Dual Column View</string> + </property> + </action> + </widget> + <resources/> + <connections/> +</ui> |