diff options
author | Weblate <noreply@weblate.org> | 2016-10-03 12:09:26 +0000 |
---|---|---|
committer | Weblate <noreply@weblate.org> | 2016-10-03 12:09:26 +0000 |
commit | f836ad04f629640db6c8076bf335d849eed64294 (patch) | |
tree | eecfd74a4d7ba31489c8d76c70f900dacd1541d5 /src-qt5/desktop-utils/lumina-fm | |
parent | Translated using Weblate (l_FILEINFO@ja (generated)) (diff) | |
parent | Fix up some instability within lumina-fileinfo. (diff) | |
download | lumina-f836ad04f629640db6c8076bf335d849eed64294.tar.gz lumina-f836ad04f629640db6c8076bf335d849eed64294.tar.bz2 lumina-f836ad04f629640db6c8076bf335d849eed64294.zip |
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'src-qt5/desktop-utils/lumina-fm')
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/Browser.cpp | 101 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/Browser.h | 29 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/BrowserWidget.cpp | 343 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/BrowserWidget.h | 101 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/DirData.h | 35 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/MainUI.cpp | 176 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/MainUI.h | 21 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/MainUI.ui | 29 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/lumina-fm.pro | 14 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/main.cpp | 12 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/widgets/DDListWidgets.h | 87 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.cpp | 2 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.h | 45 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.cpp | 695 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.h | 178 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.ui | 249 |
16 files changed, 1816 insertions, 301 deletions
diff --git a/src-qt5/desktop-utils/lumina-fm/Browser.cpp b/src-qt5/desktop-utils/lumina-fm/Browser.cpp index b207604c..7455e5ea 100644 --- a/src-qt5/desktop-utils/lumina-fm/Browser.cpp +++ b/src-qt5/desktop-utils/lumina-fm/Browser.cpp @@ -6,11 +6,20 @@ //=========================================== #include "Browser.h" +#include <QStringList> +#include <QTimer> +#include <QtConcurrent> +#include <QDebug> + +#include <LuminaUtils.h> + Browser::Browser(QObject *parent) : QObject(parent){ watcher = new QFileSystemWatcher(this); connect(watcher, SIGNAL(fileChanged(const QString&)), this, SLOT(fileChanged(QString)) ); connect(watcher, SIGNAL(directoryChanged(const QString&)), this, SLOT(dirChanged(QString)) ); showHidden = false; + imageFormats = LUtils::imageExtensions(false); //lowercase suffixes + connect(this, SIGNAL(threadDone(QString, QByteArray)), this, SLOT(futureFinished(QString, QByteArray)), Qt::QueuedConnection); //will always be between different threads } Browser::~Browser(){ @@ -30,52 +39,100 @@ bool Browser::showingHiddenFiles(){ } // PRIVATE -void Browser::loadItem(QFileInfo info){ - LFileInfo linfo(info); - QIcon ico; - if(linfo.isImage()){ - QPixmap pix; - if(pix.load(info.absoluteFilePath()) ){ - if(pix.height()>128){ pix = pix.scaled(128, 128, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); } - ico.addPixmap(pix); +void Browser::loadItem(QString info){ + //qDebug() << "LoadItem:" << info; + ////FileItem item; + //itemame = info; + QByteArray bytes; + if(imageFormats.contains(info.section(".",-1).toLower()) ){ + QFile file(info); + if(file.open(QIODevice::ReadOnly)){ + bytes = file.readAll(); + file.close(); } - }else if(linfo.isDirectory()){ - ico = LXDG::findIcon("folder","inode/directory"); + + /*QPixmap pix; + if(pix.load(item.info.absoluteFilePath()) ){ + if(pix.height()>128){ pix = pix.scaled(128, 128, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); } + item.icon.addPixmap(pix); + }*/ + }/*else if(item.info.isDir()){ + item.icon = LXDG::findIcon("folder","inode/directory"); } - if(ico.isNull()){ ico = LXDG::findIcon(linfo.mimetype(), "unknown"); } - emit ItemDataAvailable(ico, linfo); + if(item.icon.isNull()){ item.icon = LXDG::findIcon(item.info.mimetype(), "unknown"); }*/ + //qDebug() << " - done with item:" << info; + emit threadDone(info, bytes); + //return item; } // PRIVATE SLOTS void Browser::fileChanged(QString file){ - if(file.startsWith(currentDir+"/")){ emit itemUpdated(file); } + if(file.startsWith(currentDir+"/")){ QtConcurrent::run(this, &Browser::loadItem, file ); } else if(file==currentDir){ QTimer::singleShot(0, this, SLOT(loadDirectory()) ); } } void Browser::dirChanged(QString dir){ if(dir==currentDir){ QTimer::singleShot(0, this, SLOT(loadDirectory()) ); } - else if(dir.startsWith(currentDir)){ emit itemUpdated(dir); } + else if(dir.startsWith(currentDir)){ QtConcurrent::run(this, &Browser::loadItem, dir ); } +} + +void Browser::futureFinished(QString name, QByteArray icon){ + //Note: this will be called once for every item that loads + QIcon ico; + LFileInfo info(name); + if(!icon.isEmpty()){ + QPixmap pix; + if(pix.loadFromData(icon) ){ ico.addPixmap(pix); } + }else if(info.isDir()){ + ico = LXDG::findIcon("folder","inode/directory"); + } + if(ico.isNull()){ + //qDebug() << "MimeType:" << info.fileName() << info.mimetype(); + ico = LXDG::findIcon( info.iconfile(), "unknown" ); + } + this->emit itemDataAvailable( ico, info ); } // PUBLIC SLOTS -QString Browser::loadDirectory(QString dir){ +void Browser::loadDirectory(QString dir){ + //qDebug() << "Load Directory" << dir; if(dir.isEmpty()){ dir = currentDir; } //reload current directory if(dir.isEmpty()){ return; } //nothing to do - nothing previously loaded + if(currentDir != dir){ //let the main widget know to clear all current items (completely different dir) + oldFiles.clear(); + emit clearItems(); + } + currentDir = dir; //save this for later //clean up the watcher first QStringList watched; watched << watcher->files() << watcher->directories(); if(!watched.isEmpty()){ watcher->removePaths(watched); } - emit clearItems(); //let the main widget know to clear all current items - //QApplication::processEvents(); + QStringList old = oldFiles; //copy this over for the moment (both lists will change in a moment) + oldFiles.clear(); //get ready for re-creating this list // read the given directory QDir directory(dir); if(directory.exists()){ - QFileInfoList files; - if(showHidden){ files = directory.entryInfoList( QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotOrDotDot, QDir::NoSort); } - else{ files = directory.entryInfoList( QDir::Dirs | QDir::Files | QDir::NoDotOrDotDot, QDir::NoSort); } + QStringList files; + if(showHidden){ files = directory.entryList( QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot, QDir::NoSort); } + else{ files = directory.entryList( QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, QDir::NoSort); } + emit itemsLoading(files.length()); + QCoreApplication::processEvents(); for(int i=0; i<files.length(); i++){ - watcher->addPath(files[i].absoluteFilePath()); - QtConcurrent::run(this, &Browser::loadDirectory, files[i]); + watcher->addPath(directory.absoluteFilePath(files[i])); + //qDebug() << "Future Starting:" << files[i]; + QString path = directory.absoluteFilePath(files[i]); + if(old.contains(path)){ old.removeAll(path); } + oldFiles << path; //add to list for next time + QtConcurrent::run(this, &Browser::loadItem, path ); + QCoreApplication::sendPostedEvents(); } watcher->addPath(directory.absolutePath()); + if(!old.isEmpty()){ + old.removeAll(directory.absolutePath()); + for(int i=0; i<old.length(); i++){ + emit itemRemoved(old[i]); + } + } + }else{ + emit itemsLoading(0); //nothing to load } } diff --git a/src-qt5/desktop-utils/lumina-fm/Browser.h b/src-qt5/desktop-utils/lumina-fm/Browser.h index ccc10c02..7b180da9 100644 --- a/src-qt5/desktop-utils/lumina-fm/Browser.h +++ b/src-qt5/desktop-utils/lumina-fm/Browser.h @@ -9,6 +9,22 @@ #ifndef _LUMINA_FM_BROWSE_BACKEND_H #define _LUMINA_FM_BROWSE_BACKEND_H +#include <QObject> +#include <QString> +#include <QFileSystemWatcher> +#include <QIcon> +//#include <QFutureWatcher> + +#include <LuminaXDG.h> +/*class FileItem{ +public: + QString name; + QByteArray icon; + + FileItem(){} + ~FileItem(){}; +};*/ + class Browser : public QObject{ Q_OBJECT public: @@ -19,29 +35,36 @@ public: void showHiddenFiles(bool); bool showingHiddenFiles(); + //FileItem loadItem(QString info); //this is the main loader class - multiple instances each run in a separate thread + private: QString currentDir; QFileSystemWatcher *watcher; bool showHidden; + QStringList imageFormats, oldFiles; - void loadItem(QFileInfo info); //this is the main loader class - multiple instances each run in a separate thread + void loadItem(QString info); //this is the main loader class - multiple instances each run in a separate thread private slots: void fileChanged(QString); //tied into the watcher - for file change notifications void dirChanged(QString); // tied into the watcher - for new/removed files in the current dir + void futureFinished(QString, QByteArray); + public slots: - QString loadDirectory(QString dir = ""); + void loadDirectory(QString dir = ""); signals: //Main Signals - void itemUpdated(QString item); //emitted if a file changes after the initial scan + void itemRemoved(QString item); //emitted if a file was removed from the underlying void clearItems(); //emitted when dirs change for example void itemDataAvailable(QIcon, LFileInfo); //Start/Stop signals for loading of data void itemsLoading(int); //number of items which are getting loaded + //Internal signal for the alternate threads + void threadDone(QString, QByteArray); }; #endif diff --git a/src-qt5/desktop-utils/lumina-fm/BrowserWidget.cpp b/src-qt5/desktop-utils/lumina-fm/BrowserWidget.cpp index 12fd36fe..e007b974 100644 --- a/src-qt5/desktop-utils/lumina-fm/BrowserWidget.cpp +++ b/src-qt5/desktop-utils/lumina-fm/BrowserWidget.cpp @@ -5,19 +5,31 @@ // See the LICENSE file for full details //=========================================== #include "BrowserWidget.h" + +#include <QVBoxLayout> +#include <QTimer> +#include <QSettings> + +#include <LuminaUtils.h> +#include <LuminaOS.h> + BrowserWidget::BrowserWidget(QString objID, QWidget *parent) : QWidget(parent){ //Setup the Widget/UI this->setLayout( new QVBoxLayout(this) ); - + ID = objID; //Setup the backend browser object BROWSER = new Browser(this); connect(BROWSER, SIGNAL(clearItems()), this, SLOT(clearItems()) ); - connect(BROWSER, SIGNAL(itemUpdated(QString)), this, SLOT(itemUpdated(QString)) ); - connect(BROWSER, SIGNAL(itemUpdated(QString)), this, SLOT(itemUpdated(QString)) ); - connect(BROWSER, SIGNAL(itemUpdated(QString)), this, SLOT(itemUpdated(QString)) ); - + connect(BROWSER, SIGNAL(itemRemoved(QString)), this, SLOT(itemRemoved(QString)) ); + connect(BROWSER, SIGNAL(itemDataAvailable(QIcon, LFileInfo)), this, SLOT(itemDataAvailable(QIcon, LFileInfo)) ); + connect(BROWSER, SIGNAL(itemsLoading(int)), this, SLOT(itemsLoading(int)) ); + connect(this, SIGNAL(dirChange(QString)), BROWSER, SLOT(loadDirectory(QString)) ); listWidget = 0; treeWidget = 0; + readDateFormat(); + freshload = true; //nothing loaded yet + numItems = 0; + } BrowserWidget::~BrowserWidget(){ @@ -25,46 +37,341 @@ BrowserWidget::~BrowserWidget(){ } void BrowserWidget::changeDirectory(QString dir){ + qDebug() << "Change Directory:" << dir << historyList; if(BROWSER->currentDirectory()==dir){ return; } //already on this directory - BROWSER->loadDirectory(dir); + + if( !dir.contains("/.zfs/snapshot/") ){ + if(historyList.isEmpty() || !dir.isEmpty()){ historyList << dir; } + }else{ + //Need to remove the zfs snapshot first and ensure that it is not the same dir (just a diff snapshot) + QString cleaned = dir.replace( QRegExp("/\\.zfs/snapshot/(.)+/"), "/" ); + if( (historyList.isEmpty() || historyList.last()!=cleaned) && !cleaned.isEmpty() ){ historyList << cleaned; } + } + qDebug() << "History:" << historyList; + emit dirChange(dir); +} + +void BrowserWidget::showDetails(bool show){ + //Clean up widgets first + QSize iconsize; + if(show && listWidget!=0){ + //Clean up list widget + iconsize = listWidget->iconSize(); + this->layout()->removeWidget(listWidget); + listWidget->deleteLater(); + listWidget = 0; + }else if(!show && treeWidget!=0){ + iconsize = treeWidget->iconSize(); + this->layout()->removeWidget(treeWidget); + treeWidget->deleteLater(); + treeWidget = 0; + } + qDebug() << "Create Widget: details:" << show; + //Now create any new widgets + if(show && treeWidget == 0){ + treeWidget = new DDTreeWidget(this); + treeWidget->setContextMenuPolicy(Qt::CustomContextMenu); + if(!iconsize.isNull()){ treeWidget->setIconSize(iconsize); } + this->layout()->addWidget(treeWidget); + connect(treeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SIGNAL(itemsActivated()) ); + connect(treeWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SIGNAL(contextMenuRequested()) ); + connect(treeWidget, SIGNAL(DataDropped(QString, QStringList)), this, SIGNAL(DataDropped(QString, QStringList)) ); + connect(treeWidget, SIGNAL(GotFocus()), this, SLOT(selectionChanged()) ); + retranslate(); + treeWidget->sortItems(0, Qt::AscendingOrder); + if(!BROWSER->currentDirectory().isEmpty()){ emit dirChange(""); } + }else if(!show && listWidget==0){ + listWidget = new DDListWidget(this); + listWidget->setContextMenuPolicy(Qt::CustomContextMenu); + if(!iconsize.isNull()){ listWidget->setIconSize(iconsize); } + this->layout()->addWidget(listWidget); + connect(listWidget, SIGNAL(itemActivated(QListWidgetItem*)), this, SIGNAL(itemsActivated()) ); + connect(listWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SIGNAL(contextMenuRequested()) ); + connect(listWidget, SIGNAL(DataDropped(QString, QStringList)), this, SIGNAL(DataDropped(QString, QStringList)) ); + connect(listWidget, SIGNAL(GotFocus()), this, SLOT(selectionChanged()) ); + if(!BROWSER->currentDirectory().isEmpty()){ emit dirChange(""); } + } + qDebug() << " Done making widget"; +} + +bool BrowserWidget::hasDetails(){ + return (treeWidget!=0); +} + +void BrowserWidget::showHiddenFiles(bool show){ + BROWSER->showHiddenFiles(show); +} + +bool BrowserWidget::hasHiddenFiles(){ + return BROWSER->showingHiddenFiles(); +} + +void BrowserWidget::setThumbnailSize(int px){ + bool larger = true; + if(listWidget!=0){ + larger = listWidget->iconSize().height() < px; + listWidget->setIconSize(QSize(px,px)); + }else if(treeWidget!=0){ + larger = treeWidget->iconSize().height() < px; + treeWidget->setIconSize(QSize(px,px)); + } + //qDebug() << "Changing Icon Size:" << px << larger; + if(BROWSER->currentDirectory().isEmpty() || !larger ){ return; } //don't need to reload icons unless the new size is larger + emit dirChange(""); +} + +int BrowserWidget::thumbnailSize(){ + if(listWidget!=0){ return listWidget->iconSize().height(); } + else if(treeWidget!=0){ return treeWidget->iconSize().height(); } + return 0; +} + +void BrowserWidget::setHistory(QStringList paths){ + //NOTE: later items are used first + historyList = paths; +} + +QStringList BrowserWidget::history(){ + return historyList; +} + +void BrowserWidget::setShowActive(bool show){ + if(!show){ this->setStyleSheet("QAbstractScrollArea{ background-color: rgba(10,10,10,10); }"); } + else{ + this->setStyleSheet( "QAbstractScrollArea{ background-color: white; }"); + } +} + +// 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 BrowserWidget::readDateFormat() { + if(!date_format.isEmpty()) + date_format.clear(); + QSettings settings("lumina-desktop","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(); +} + + +QStringList BrowserWidget::currentSelection(){ + QStringList out; + if(listWidget!=0){ + QList<QListWidgetItem*> sel = listWidget->selectedItems(); + //qDebug() << "Selection number:" << sel.length(); + //if(sel.isEmpty() && listWidget->currentItem()!=0){ sel << listWidget->currentItem(); } + //qDebug() << "Selection number:" << sel.length(); + for(int i=0; i<sel.length(); i++){ out << sel[i]->whatsThis(); qDebug() << "Selection:" << sel[i]->text() << sel[i]->whatsThis(); } + }else if(treeWidget!=0){ + QList<QTreeWidgetItem*> sel = treeWidget->selectedItems(); + //if(sel.isEmpty() && treeWidget->currentItem()!=0){ sel << treeWidget->currentItem(); } + for(int i=0; i<sel.length(); i++){ out << sel[i]->whatsThis(0); } + } + out.removeDuplicates(); //just in case - tree widgets sometimes "select" each column as an individual item + return out; +} + +QStringList BrowserWidget::currentItems(int type){ + //type: 0=all, -1=files, +1=dirs + QStringList paths; + if(listWidget!=0){ + for(int i=0; i<listWidget->count(); i++){ + if(i<0 && (listWidget->item(i)->data(Qt::UserRole).toString()=="file") ){ //FILES + paths << listWidget->item(i)->whatsThis(); + }else if(i>0 && (listWidget->item(i)->data(Qt::UserRole).toString()=="dir")){ //DIRS + paths << listWidget->item(i)->whatsThis(); + }else if(i==0){ //ALL + paths << listWidget->item(i)->whatsThis(); + } + } + }else if(treeWidget!=0){ + for(int i=0; i<treeWidget->topLevelItemCount(); i++){ + if(i<0 && !treeWidget->topLevelItem(i)->text(1).isEmpty()){ //FILES + paths << treeWidget->topLevelItem(i)->whatsThis(0); + }else if(i>0 && treeWidget->topLevelItem(i)->text(1).isEmpty()){ //DIRS + paths << treeWidget->topLevelItem(i)->whatsThis(0); + }else if(i==0){ //ALL + paths << treeWidget->topLevelItem(i)->whatsThis(0); + } + } + } + return paths; +} + +// ================= +// PUBLIC SLOTS +// ================= +void BrowserWidget::retranslate(){ + if(listWidget!=0){ + + }else if(treeWidget!=0){ + QTreeWidgetItem *it = new QTreeWidgetItem(); + it->setText(0,tr("Name")); + it->setText(1,tr("Size")); + it->setText(2, tr("Type")); + it->setText(3, tr("Date Modified") ); + it->setText(4, tr("Date Created") ); + treeWidget->setHeaderItem(it); + //Now reset the sorting (alphabetically, dirs first) + treeWidget->sortItems(0, Qt::AscendingOrder); // sort by name + treeWidget->sortItems(1, Qt::AscendingOrder); //sort by type + } +} + +// ================= +// PRIVATE +// ================= +QString BrowserWidget::DTtoString(QDateTime dt){ + QStringList fmt = date_format; + if(fmt.isEmpty() || fmt.length()!=2 || (fmt[0].isEmpty() && fmt[1].isEmpty()) ){ + //Default formatting + return dt.toString(Qt::DefaultLocaleShortDate); + }else if(fmt[0].isEmpty()){ + //Time format only + return (dt.date().toString(Qt::DefaultLocaleShortDate)+" "+dt.time().toString(fmt[1])); + }else if(fmt[1].isEmpty()){ + //Date format only + return (dt.date().toString(fmt[0])+" "+dt.time().toString(Qt::DefaultLocaleShortDate)); + }else{ + //both date/time formats set + return dt.toString(fmt.join(" ")); + } } // ================= // PRIVATE SLOTS // ================= void BrowserWidget::clearItems(){ + //qDebug() << "Clear Items"; if(listWidget!=0){ listWidget->clear(); } else if(treeWidget!=0){ treeWidget->clear(); } - this->setEnabled(false); + freshload = true; } -void BrowserWidget::itemUpdated(QString item){ - if(treeWidget==0){ return; } //only used for the tree widget/details - qDebug() << "item updated" << item; - QList<QTreeWidgetItem*> found = treeWidget->findItems(item.section("/",-1), Qt::MatchExactly, 0); //look for exact name match - if(found.isEmpty()){ return; } //no match - QTreeWidgetItem *it = found[0]; //onlyp update the first match (should only ever be one - duplicate file names are disallowed) - //it->setText( +void BrowserWidget::itemRemoved(QString item){ + //qDebug() << "item removed" << item; + if(treeWidget!=0){ + QList<QTreeWidgetItem*> found = treeWidget->findItems(item.section("/",-1), Qt::MatchExactly, 0); //look for exact name match + if(found.isEmpty()){ return; } //no match + delete found[0]; + }else if(listWidget!=0){ + QList<QListWidgetItem*> found = listWidget->findItems(item.section("/",-1), Qt::MatchExactly); //look for exact name match + if(found.isEmpty()){ return; } + delete found[0]; + } } void BrowserWidget::itemDataAvailable(QIcon ico, LFileInfo info){ + //qDebug() << "Item Data Available:" << info.fileName(); int num = 0; if(listWidget!=0){ - listWidget->addItem( new QListWidgetItem(ico, info.fileName(), listWidget) ); + //LIST WIDGET - name and icon only + if(!listWidget->findItems(info.fileName(), Qt::MatchExactly).isEmpty()){ + //Update existing item + QListWidgetItem *it = listWidget->findItems(info.fileName(), Qt::MatchExactly).first(); + it->setText(info.fileName()); + it->setWhatsThis(info.absoluteFilePath()); + it->setIcon(ico); + }else{ + //New item + QListWidgetItem *it = new CQListWidgetItem(ico, info.fileName(), listWidget); + it->setWhatsThis(info.absoluteFilePath()); + it->setData(Qt::UserRole, (info.isDir() ? "dir" : "file")); //used for sorting + listWidget->addItem(it); + } num = listWidget->count(); }else if(treeWidget!=0){ - //TODO + QTreeWidgetItem *it = 0; + if( ! treeWidget->findItems(info.fileName(), Qt::MatchExactly, 0).isEmpty() ){ it = treeWidget->findItems(info.fileName(), Qt::MatchExactly, 0).first(); } + else{ + it = new CQTreeWidgetItem(treeWidget); + it->setText(0, info.fileName() ); //name (0) + treeWidget->addTopLevelItem(it); + } + //Now set/update all the data + it->setIcon(0, ico); + it->setText(1, info.isDir() ? "" : LUtils::BytesToDisplaySize(info.size()) ); //size (1) + it->setText(2, info.mimetype() ); //type (2) + it->setText(3, DTtoString(info.lastModified() )); //modification date (3) + it->setText(4, DTtoString(info.created()) ); //creation date (4) + //Now all the hidden data + it->setWhatsThis(0, info.absoluteFilePath()); + it->setWhatsThis(3, info.lastModified().toString("yyyyMMddhhmmsszzz") ); //sorts by this actually + it->setWhatsThis(4, info.created().toString("yyyyMMddhhmmsszzz") ); //sorts by this actually + num = treeWidget->topLevelItemCount(); } if(num < numItems){ //Still loading items //this->setEnabled(false); }else{ + if(freshload && treeWidget!=0){ + //qDebug() << "Resize Tree Widget Contents"; + for(int i=0; i<treeWidget->columnCount(); i++){ treeWidget->resizeColumnToContents(i); } + } + freshload = false; //any further changes are updates - not a fresh load of a dir //Done loading items - this->setEnabled(true); - } + //this->setEnabled(true); + //Assemble any status message + QString stats = QString(tr("Capacity: %1")).arg(LOS::FileSystemCapacity(BROWSER->currentDirectory())); + int nF, nD; + double bytes = 0; + nF = nD = 0; + if(listWidget!=0){ + bytes = -1; //not supported for this widget + for(int i=0; i<listWidget->count(); i++){ + if(listWidget->item(i)->data(Qt::UserRole).toString()=="dir"){ nD++; } //directory + else{ nF++; } //file + } + }else if(treeWidget!=0){ + for(int i=0; i<treeWidget->topLevelItemCount(); i++){ + if(treeWidget->topLevelItem(i)->text(1).isEmpty()){ + nD++; //directory + }else{ + nF++; //file + bytes+=LUtils::DisplaySizeToBytes(treeWidget->topLevelItem(i)->text(1)); + } + } + } + + if( (nF+nD) >0){ + stats.prepend("\t"); + if(nF>0){ + //Has Files + if(bytes>0){ + stats.prepend( QString(tr("Files: %1 (%2)")).arg(QString::number(nF), LUtils::BytesToDisplaySize(bytes)) ); + }else{ + stats.prepend( QString(tr("Files: %1")).arg(QString::number(nF)) ); + } + } + if(nD > 0){ + //Has Dirs + if(nF>0){ stats.prepend(" / "); }//has files output already + stats.prepend( QString(tr("Dirs: %1")).arg(QString::number(nD)) ); + } + } + emit updateDirectoryStatus( stats.simplified() ); + statustip = stats.simplified(); //save for later + }//end check for finished loading items } void BrowserWidget::itemsLoading(int total){ + //qDebug() << "Got number of items loading:" << total; numItems = total; //save this for later + if(total<1){ + emit updateDirectoryStatus( tr("No Directory Contents") ); + this->setEnabled(true); + } +} + +void BrowserWidget::selectionChanged(){ + emit hasFocus(ID); //let the parent know the widget is "active" with the user } +void BrowserWidget::resizeEvent(QResizeEvent *ev){ + QWidget::resizeEvent(ev); //do the normal processing first + //The list widget needs to be poked to rearrange the items to fit the new size + // tree widget does this fine at the moment. + if(listWidget!=0){ + listWidget->sortItems(Qt::AscendingOrder); + } +} diff --git a/src-qt5/desktop-utils/lumina-fm/BrowserWidget.h b/src-qt5/desktop-utils/lumina-fm/BrowserWidget.h index a0dc535a..803a036d 100644 --- a/src-qt5/desktop-utils/lumina-fm/BrowserWidget.h +++ b/src-qt5/desktop-utils/lumina-fm/BrowserWidget.h @@ -8,21 +8,29 @@ #ifndef _LUMINA_FM_BROWSE_FRONTEND_H #define _LUMINA_FM_BROWSE_FRONTEND_H +#include <QString> +#include <QWidget> +#include <QThread> + #include "Browser.h" #include "widgets/DDListWidgets.h" class BrowserWidget : public QWidget{ Q_OBJECT private: - Browser *DIR: - QString ID; + Browser *BROWSER; + //QThread *bThread; //browserThread int numItems; //used for checking if all the items have loaded yet - bool details; //show details or not + QString ID, statustip; + QStringList date_format, historyList; + bool freshload; //The drag and drop brower widgets DDListWidget *listWidget; DDTreeWidget *treeWidget; + QString DTtoString(QDateTime dt); //QDateTime to string simplification routine + public: BrowserWidget(QString objID, QWidget *parent = 0); ~BrowserWidget(); @@ -30,68 +38,55 @@ public: QString id(){ return ID; } void changeDirectory(QString dir); + QString currentDirectory(){ return BROWSER->currentDirectory(); } void showDetails(bool show); bool hasDetails(); + void showHiddenFiles(bool show); + bool hasHiddenFiles(); + + void setThumbnailSize(int px); + int thumbnailSize(); + + void setHistory(QStringList); + QStringList history(); + + void setShowActive(bool show); //used for accenting if the widget is "active" + + QString status(){ return statustip; } + + //Date format for show items + void readDateFormat(); + + //Return all the items which are currently selected + QStringList currentSelection(); + QStringList currentItems(int type = 0); //type: 0=all, -1=files, +1=dirs + public slots: + void retranslate(); private slots: - //Brower connections + //Browser connections void clearItems(); - void itemUpdated(QString); + void itemRemoved(QString); void itemDataAvailable(QIcon, LFileInfo); void itemsLoading(int total); + void selectionChanged(); + +protected: + void resizeEvent(QResizeEvent *ev); signals: - //void activated(QString); //current dir path - void dirChanged(QString); //current dir path + //External signals + void itemsActivated(); + void updateDirectoryStatus(QString); + void contextMenuRequested(); + void DataDropped(QString, QStringList); + void hasFocus(QString); //ID output + + //Internal signal + void dirChange(QString); //current dir path -}; - -/* - * 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/DirData.h b/src-qt5/desktop-utils/lumina-fm/DirData.h index c3ace5a4..546dd6c5 100644 --- a/src-qt5/desktop-utils/lumina-fm/DirData.h +++ b/src-qt5/desktop-utils/lumina-fm/DirData.h @@ -32,6 +32,7 @@ public: QString dirpath; //directory this structure was reading QString snapdir; //base snapshot directory (if one was requested/found) bool hashidden; + QStringList mntpoints; //Access Functions LDirInfoList(QString path = ""){ @@ -39,6 +40,11 @@ public: list.clear(); fileNames.clear(); hashidden = false; + //Generate the list of all mountpoints if possible + if(LUtils::isValidBinary("zfs")){ + mntpoints = LUtils::getCmdOutput("zfs list -H -o mountpoint").filter("/"); + mntpoints.removeDuplicates(); + } } ~LDirInfoList(){} @@ -72,23 +78,21 @@ public: } void findSnapDir(){ - //Search the filesystem + //Search the filesystem if(dirpath.contains(ZSNAPDIR)){ snapdir = dirpath.section(ZSNAPDIR,0,0)+ZSNAPDIR; //no need to go looking for it + }else if(mntpoints.isEmpty()){ + snapdir.clear(); //no zfs dirs available }else{ - //Need to backtrack - QDir dir(dirpath); - bool found = false; - while(dir.canonicalPath()!="/" && !found){ - //qDebug() << " -- Checking for snapshot dir:" << dir.canonicalPath(); - if(dir.exists(".zfs/snapshot")){ - snapdir = dir.canonicalPath()+ZSNAPDIR; - found = true; - }else{ - dir.cdUp(); - } - }//end loop - } + //Only check the mountpoint associated with this directory + QString mnt; + for(int i=0; i<mntpoints.length(); i++){ + if(dirpath == mntpoints[i]){ mnt = mntpoints[i]; break; } + else if(dirpath.startsWith(mntpoints[i]) && mntpoints[i].length()>mnt.length()){ mnt = mntpoints[i]; } + } + if(QFile::exists(mnt+ZSNAPDIR)){ snapdir = mnt+ZSNAPDIR; } + else{ snapdir.clear(); } //none found + } } }; @@ -119,6 +123,7 @@ public: public slots: void GetDirData(QString ID, QString dirpath){ + return; if(pauseData){ return; } if(DIR_DEBUG){ qDebug() << "GetDirData:" << ID << dirpath; } //The ID is used when returning the info in a moment @@ -146,7 +151,7 @@ public slots: //Only check if ZFS is flagged as available if(zfsavailable){ //First find if the hash already has an entry for this directory - if(false){ //!HASH.contains(dirpath)){ + if(!HASH.contains(dirpath)){ LDirInfoList info(dirpath); HASH.insert(dirpath,info); } diff --git a/src-qt5/desktop-utils/lumina-fm/MainUI.cpp b/src-qt5/desktop-utils/lumina-fm/MainUI.cpp index 59b671b5..bac365e1 100644 --- a/src-qt5/desktop-utils/lumina-fm/MainUI.cpp +++ b/src-qt5/desktop-utils/lumina-fm/MainUI.cpp @@ -15,11 +15,11 @@ MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI){ //for Signal/slot we must register the Typedef of QFileInfoList - qRegisterMetaType<QFileInfoList>("QFileInfoList"); + //qRegisterMetaType<QFileInfoList>("QFileInfoList"); qRegisterMetaType< LFileInfoList >("LFileInfoList"); //just to silence/fix some Qt connect warnings in QtConcurrent - qRegisterMetaType< QVector<int> >("QVector<int>"); - qRegisterMetaType< QList<QPersistentModelIndex> >("QList<QPersistentModelIndex>"); + //qRegisterMetaType< QVector<int> >("QVector<int>"); + //qRegisterMetaType< QList<QPersistentModelIndex> >("QList<QPersistentModelIndex>"); ui->setupUi(this); @@ -27,9 +27,6 @@ MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI){ if(DEBUG){ qDebug() << "Initilization:"; } settings = new QSettings( QSettings::UserScope, "lumina-desktop", "lumina-fm", this); - //syncTimer = new QTimer(this); - //syncTimer->setInterval(200); //1/5 second (collect as many signals/slots as necessary - //syncTimer->setSingleShot(true); //Reset the UI to the previously used size (if possible) QSize orig = settings->value("preferences/MainWindowSize", QSize()).toSize(); if(!orig.isEmpty() && orig.isValid()){ @@ -56,34 +53,29 @@ QSize orig = settings->value("preferences/MainWindowSize", QSize()).toSize(); workThread->setObjectName("Lumina-fm filesystem worker"); worker = new DirData(); worker->zfsavailable = LUtils::isValidBinary("zfs"); - connect(worker, SIGNAL(DirDataAvailable(QString, QString, LFileInfoList)), this, SLOT(DirDataAvailable(QString, QString, LFileInfoList)) ); + //connect(worker, SIGNAL(DirDataAvailable(QString, QString, LFileInfoList)), this, SLOT(DirDataAvailable(QString, QString, LFileInfoList)) ); connect(worker, SIGNAL(SnapshotDataAvailable(QString, QString, QStringList)), this, SLOT(SnapshotDataAvailable(QString, QString, QStringList)) ); worker->moveToThread(workThread); - //if(DEBUG){ qDebug() << " - File System Model"; } - //fsmod = new QFileSystemModel(this); - //fsmod->setRootPath(QDir::homePath()); - //dirCompleter = new QCompleter(fsmod, this); - //dirCompleter->setModelSorting( QCompleter::CaseInsensitivelySortedModel ); if(DEBUG){ qDebug() << " - Context Menu"; } contextMenu = new QMenu(this); radio_view_details = new QRadioButton(tr("Detailed List"), this); radio_view_list = new QRadioButton(tr("Basic List"), this); - radio_view_tabs = new QRadioButton(tr("Prefer Tabs"), this); - radio_view_cols = new QRadioButton(tr("Prefer Columns"), this); + //radio_view_tabs = new QRadioButton(tr("Prefer Tabs"), this); + //radio_view_cols = new QRadioButton(tr("Prefer Columns"), this); ui->menuView_Mode->clear(); - ui->menuGroup_Mode->clear(); + //ui->menuGroup_Mode->clear(); detWA = new QWidgetAction(this); detWA->setDefaultWidget(radio_view_details); listWA = new QWidgetAction(this); listWA->setDefaultWidget(radio_view_list); - tabsWA = new QWidgetAction(this); - tabsWA->setDefaultWidget(radio_view_tabs); - colsWA = new QWidgetAction(this); - colsWA->setDefaultWidget(radio_view_cols); + //tabsWA = new QWidgetAction(this); + //tabsWA->setDefaultWidget(radio_view_tabs); + //colsWA = new QWidgetAction(this); + //colsWA->setDefaultWidget(radio_view_cols); ui->menuView_Mode->addAction(detWA); ui->menuView_Mode->addAction(listWA); - ui->menuGroup_Mode->addAction(tabsWA); - ui->menuGroup_Mode->addAction(colsWA); + //ui->menuGroup_Mode->addAction(tabsWA); + //ui->menuGroup_Mode->addAction(colsWA); //Setup the pages //ui->BrowserLayout->clear(); ui->page_player->setLayout(new QVBoxLayout()); @@ -113,8 +105,6 @@ QSize orig = settings->value("preferences/MainWindowSize", QSize()).toSize(); if(DEBUG){ qDebug() << " - Devices"; } RebuildDeviceMenu(); //Make sure we start on the browser page - if(DEBUG){ qDebug() << " - Load Browser Page"; } - //goToBrowserPage(); if(DEBUG){ qDebug() << " - Done with init"; } } @@ -149,7 +139,7 @@ void MainUI::OpenDirs(QStringList dirs){ DWLIST << DW; //Connect the signals/slots for it connect(DW, SIGNAL(OpenDirectories(QStringList)), this, SLOT(OpenDirs(QStringList)) ); - connect(DW, SIGNAL(LoadDirectory(QString, QString)), worker, SLOT(GetDirData(QString, QString)) ); + //connect(DW, SIGNAL(LoadDirectory(QString, QString)), worker, SLOT(GetDirData(QString, QString)) ); connect(DW, SIGNAL(findSnaps(QString, QString)), worker, SLOT(GetSnapshotData(QString, QString)) ); connect(DW, SIGNAL(PlayFiles(LFileInfoList)), this, SLOT(OpenPlayer(LFileInfoList)) ); connect(DW, SIGNAL(ViewFiles(LFileInfoList)), this, SLOT(OpenImages(LFileInfoList)) ); @@ -161,12 +151,13 @@ void MainUI::OpenDirs(QStringList dirs){ connect(DW, SIGNAL(RemoveFiles(QStringList)), this, SLOT(RemoveFiles(QStringList)) ); connect(DW, SIGNAL(PasteFiles(QString,QStringList)), this, SLOT(PasteFiles(QString, QStringList)) ); connect(DW, SIGNAL(CloseBrowser(QString)), this, SLOT(CloseBrowser(QString)) ); + connect(DW, SIGNAL(TabNameChanged(QString,QString)), this, SLOT(TabNameChanged(QString, QString)) ); //Now create the tab for this - if(radio_view_tabs->isChecked()){ + //if(radio_view_tabs->isChecked()){ int index = tabBar->addTab( LXDG::findIcon("folder-open",""), dirs[i].section("/",-1) ); tabBar->setTabWhatsThis( index, "DW-"+QString::number(id) ); tabBar->setCurrentIndex(index); - }else{ + /*}else{ //Just make sure the browser tab is visible bool found = false; for(int i=0; i<tabBar->count() && !found; i++){ @@ -178,17 +169,11 @@ void MainUI::OpenDirs(QStringList dirs){ tabBar->setTabWhatsThis( index, "browser" ); tabBar->setCurrentIndex(index); } - } + }*/ //Initialize the widget with the proper settings - DW->setShowDetails(radio_view_details->isChecked()); - DW->setShowSidebar(ui->actionShow_Action_Buttons->isChecked()); - QList<DirWidget::DETAILTYPES> details; details <<DirWidget::NAME << DirWidget::SIZE << DirWidget::TYPE << DirWidget::DATEMOD; - DW->setDetails(details); //Which details to show and in which order (L->R) - DW->setShowThumbnails(ui->actionShow_Thumbnails->isChecked()); + DW->setShowDetails(radio_view_details->isChecked()); DW->setThumbnailSize(settings->value("iconsize", 32).toInt()); - //DW->setDirCompleter(dirCompleter); - DW->setShowCloseButton(!radio_view_tabs->isChecked()); //Now load the directory DW->ChangeDir(dirs[i]); //kick off loading the directory info } @@ -225,9 +210,6 @@ void MainUI::setupIcons(){ // View menu ui->actionRefresh->setIcon( LXDG::findIcon("view-refresh","") ); ui->menuView_Mode->setIcon( LXDG::findIcon("view-choose","") ); - ui->menuGroup_Mode->setIcon( LXDG::findIcon("tab-duplicate","") ); - ui->actionLarger_Icons->setIcon( LXDG::findIcon("zoom-in","") ); - ui->actionSmaller_Icons->setIcon( LXDG::findIcon("zoom-out", "") ); // Bookmarks menu ui->actionManage_Bookmarks->setIcon( LXDG::findIcon("bookmarks-organize","") ); @@ -253,8 +235,8 @@ void MainUI::setupConnections(){ //Radio Buttons connect(radio_view_details, SIGNAL(toggled(bool)), this, SLOT(viewModeChanged(bool)) ); connect(radio_view_list, SIGNAL(toggled(bool)), this, SLOT(viewModeChanged(bool)) ); - connect(radio_view_tabs, SIGNAL(toggled(bool)), this, SLOT(groupModeChanged(bool)) ); - connect(radio_view_cols, SIGNAL(toggled(bool)), this, SLOT(groupModeChanged(bool)) ); + //connect(radio_view_tabs, SIGNAL(toggled(bool)), this, SLOT(groupModeChanged(bool)) ); + //connect(radio_view_cols, SIGNAL(toggled(bool)), this, SLOT(groupModeChanged(bool)) ); //Special Keyboard Shortcuts connect(nextTabLShort, SIGNAL(activated()), this, SLOT( prevTab() ) ); @@ -280,25 +262,28 @@ void MainUI::togglehiddenfiles() void MainUI::loadSettings(){ //Note: make sure this is run after all the UI elements are created and connected to slots // but before the first directory gets loaded - ui->actionView_Hidden_Files->setChecked( settings->value("showhidden", false).toBool() ); + QSettings SET("lumina-desktop","lumina-fm"); + ui->actionView_Hidden_Files->setChecked( SET.value("showhidden", false).toBool() ); on_actionView_Hidden_Files_triggered(); //make sure to update the models too - ui->actionShow_Action_Buttons->setChecked(settings->value("showactions", true).toBool() ); - on_actionShow_Action_Buttons_triggered(); //make sure to update the UI - ui->actionShow_Thumbnails->setChecked( settings->value("showthumbnails", true).toBool() ); + //ui->actionShow_Action_Buttons->setChecked(settings->value("showactions", true).toBool() ); + //on_actionShow_Action_Buttons_triggered(); //make sure to update the UI + //ui->actionShow_Thumbnails->setChecked( settings->value("showthumbnails", true).toBool() ); //View Type - bool showDetails = (settings->value("viewmode","details").toString()=="details"); + //qDebug() << "View Mode:" << SET.value("viewmode","details").toString(); + bool showDetails = (SET.value("viewmode","details").toString()=="details"); if(showDetails){ radio_view_details->setChecked(true); } else{ radio_view_list->setChecked(true); } //Grouping type - bool usetabs = (settings->value("groupmode","tabs").toString()=="tabs"); - if(usetabs){ radio_view_tabs->setChecked(true); } - else{ radio_view_cols->setChecked(true); } + //bool usetabs = (SET.value("groupmode","tabs").toString()=="tabs"); + //if(usetabs){ radio_view_tabs->setChecked(true); } + // else{ radio_view_cols->setChecked(true); } } void MainUI::RebuildBookmarksMenu(){ //Create the bookmarks menu - QStringList BM = settings->value("bookmarks", QStringList()).toStringList(); + QSettings SET("lumina-desktop","lumina-fm"); + QStringList BM = SET.value("bookmarks", QStringList()).toStringList(); ui->menuBookmarks->clear(); ui->menuBookmarks->addAction(ui->actionManage_Bookmarks); ui->menuBookmarks->addAction(ui->actionAdd_Bookmark); @@ -306,18 +291,19 @@ void MainUI::RebuildBookmarksMenu(){ bool changed = false; BM.sort(); //Sort alphabetically for(int i=0; i<BM.length(); i++){ - if(QFile::exists(BM[i].section("::::",1,1)) ){ + //NOTE 9/28/16: Don't do existance checks here - if a network drive is specified it can cause the loading process to hang significantly + //if(QFile::exists(BM[i].section("::::",1,1)) ){ QAction *act = new QAction(BM[i].section("::::",0,0),this); act->setWhatsThis(BM[i].section("::::",1,1)); ui->menuBookmarks->addAction(act); - }else{ + /*}else{ //Invalid directory - remove the bookmark BM.removeAt(i); i--; changed = true; - } + }*/ } - if(changed){ settings->setValue("bookmarks",BM); } + if(changed){ SET.setValue("bookmarks",BM); } ui->actionManage_Bookmarks->setEnabled(BM.length()>0); } @@ -434,16 +420,16 @@ void MainUI::on_actionClose_triggered(){ this->close(); } -void MainUI::on_actionRename_triggered(){ +/*void MainUI::on_actionRename_triggered(){ DirWidget *dir = FindActiveBrowser(); if(DEBUG){ qDebug() << "Rename Shortcut Pressed:" << dir << dir->currentDir(); } - if(dir!=0){ QTimer::singleShot(0, dir, SLOT(TryRenameSelection()) ); } + if(dir!=0){ QTimer::singleShot(0, dir, SLOT(renameFiles()) ); } } void MainUI::on_actionCut_Selection_triggered(){ DirWidget *dir = FindActiveBrowser(); if(DEBUG){ qDebug() << "Cut Shortcut Pressed:" << dir << dir->currentDir(); } - if(dir!=0){ QTimer::singleShot(0, dir, SLOT(TryCutSelection()) ); } + if(dir!=0){ QTimer::singleShot(0, dir, SLOT(cutFiles()) ); } } void MainUI::on_actionCopy_Selection_triggered(){ @@ -462,7 +448,7 @@ void MainUI::on_actionDelete_Selection_triggered(){ DirWidget *dir = FindActiveBrowser(); if(DEBUG){ qDebug() << "Delete Shortcut Pressed:" << dir << dir->currentDir(); } if(dir!=0){ QTimer::singleShot(0, dir, SLOT(TryDeleteSelection()) ); } -} +}*/ void MainUI::on_actionRefresh_triggered(){ DirWidget *cur = FindActiveBrowser(); @@ -473,24 +459,24 @@ void MainUI::on_actionView_Hidden_Files_triggered(){ worker->showHidden = ui->actionView_Hidden_Files->isChecked(); //Now save this setting for later settings->setValue("showhidden", ui->actionView_Hidden_Files->isChecked()); - worker->showHidden = ui->actionView_Hidden_Files->isChecked(); + //worker->showHidden = ui->actionView_Hidden_Files->isChecked(); //Re-load the current browsers - for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->refresh(); } + for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->showHidden( ui->actionView_Hidden_Files->isChecked() ); }//DWLIST[i]->refresh(); } } -void MainUI::on_actionShow_Action_Buttons_triggered(){ +/*void MainUI::on_actionShow_Action_Buttons_triggered(){ bool show = ui->actionShow_Action_Buttons->isChecked(); settings->setValue("showactions", show); - for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->setShowSidebar(show); } -} + //for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->setShowSidebar(show); } +}*/ -void MainUI::on_actionShow_Thumbnails_triggered(){ +/*void MainUI::on_actionShow_Thumbnails_triggered(){ //Now save this setting for later bool show = ui->actionShow_Thumbnails->isChecked(); settings->setValue("showthumbnails", show); - for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->setShowThumbnails(show); } -} + //for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->setShowThumbnails(show); } +}*/ void MainUI::goToBookmark(QAction *act){ if(act==ui->actionManage_Bookmarks){ @@ -529,8 +515,9 @@ void MainUI::goToDevice(QAction *act){ void MainUI::viewModeChanged(bool active){ if(!active){ return; } //on every view change, all radio buttons will call this function - only run this once though bool showDetails = radio_view_details->isChecked(); - if(showDetails){ settings->setValue("viewmode","details"); } - else{ settings->setValue("viewmode","list"); } + QSettings SET("lumina-desktop","lumina-fm"); + if(showDetails){ SET.setValue("viewmode","details"); } + else{ SET.setValue("viewmode","list"); } //Re-load the view widgets for(int i=0; i<DWLIST.length(); i++){ @@ -539,11 +526,11 @@ void MainUI::viewModeChanged(bool active){ } -void MainUI::groupModeChanged(bool active){ +/*void MainUI::groupModeChanged(bool active){ if(!active){ return; } //on every change, all radio buttons will call this function - only run this once though - bool usetabs = radio_view_tabs->isChecked(); - if(usetabs){ - settings->setValue("groupmode","tabs"); + //bool usetabs = radio_view_tabs->isChecked(); + //if(usetabs){ + //settings->setValue("groupmode","tabs"); //Now clean up all the tabs (remove the generic one and add the specific ones) for(int i=0; i<tabBar->count(); i++){ //Remove all the browser tabs @@ -557,7 +544,7 @@ void MainUI::groupModeChanged(bool active){ qDebug() << "Add specific tab:" << DWLIST[i]->currentDir() << DWLIST[i]->id(); int tab = tabBar->addTab( LXDG::findIcon("folder-open",""), DWLIST[i]->currentDir().section("/",-1) ); tabBar->setTabWhatsThis(tab, DWLIST[i]->id() ); - DWLIST[i]->setShowCloseButton(false); + //DWLIST[i]->setShowCloseButton(false); } }else{ settings->setValue("groupmode","columns"); @@ -572,12 +559,12 @@ void MainUI::groupModeChanged(bool active){ //Now create the generic "browser" tab int tab = tabBar->addTab( LXDG::findIcon("folder-open",""), tr("Browser") ); tabBar->setTabWhatsThis(tab, "browser" ); - for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->setShowCloseButton(true); } + //for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->setShowCloseButton(true); } } if(tabBar->currentIndex()<0){ tabBar->setCurrentIndex(0); } tabBar->setVisible( tabBar->count() > 1 ); QTimer::singleShot(20, this, SLOT(tabChanged()) ); -} +}*/ void MainUI::on_actionLarger_Icons_triggered(){ int size = settings->value("iconsize", 32).toInt(); @@ -645,16 +632,16 @@ void MainUI::tabChanged(int tab){ else if(info=="#SW"){ ui->stackedWidget->setCurrentWidget(ui->page_image); } else{ ui->stackedWidget->setCurrentWidget(ui->page_browser); - if(radio_view_tabs->isChecked()){ + //if(radio_view_tabs->isChecked()){ for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->setVisible(DWLIST[i]->id()==info); } - }else{ + /*}else{ //For columns, all widgets need to be visible for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->setVisible(true); } - } + }*/ } tabBar->setVisible( tabBar->count() > 1 ); } @@ -695,22 +682,6 @@ void MainUI::nextTab(){ else{ tabBar->setCurrentIndex( cur+1 ); } } -void MainUI::DirDataAvailable(QString id, QString dir, LFileInfoList list){ - for(int i=0; i<DWLIST.length(); i++){ - if(id == DWLIST[i]->id()){ - DWLIST[i]->LoadDir(dir, list); - break; - } - } - if(radio_view_tabs->isChecked()){ - //Need to update the text for the tab so it corresponds to the current directory loaded - for(int i=0; i<tabBar->count(); i++){ - if(tabBar->tabWhatsThis(i)==id){ - tabBar->setTabText(i, dir.section("/",-1)); - } - } - } -} void MainUI::SnapshotDataAvailable(QString id , QString dir, QStringList list){ for(int i=0; i<DWLIST.length(); i++){ @@ -789,7 +760,7 @@ void MainUI::CutFiles(QStringList list){ QApplication::clipboard()->clear(); QApplication::clipboard()->setMimeData(dat); //Update all the buttons to account for clipboard change - for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->refreshButtons(); } + //for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->refreshButtons(); } } void MainUI::CopyFiles(QStringList list){ @@ -809,7 +780,7 @@ void MainUI::CopyFiles(QStringList list){ QApplication::clipboard()->clear(); QApplication::clipboard()->setMimeData(dat); //Update all the buttons to account for clipboard change - for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->refreshButtons(); } + //for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->refreshButtons(); } } void MainUI::PasteFiles(QString dir, QStringList raw){ @@ -864,7 +835,7 @@ void MainUI::PasteFiles(QString dir, QStringList raw){ } } //Update all the buttons to account for clipboard change - for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->refresh(); } + //for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->refresh(); } } void MainUI::FavoriteFiles(QStringList list){ @@ -930,13 +901,13 @@ void MainUI::RemoveFiles(QStringList list){ //Now remove the file/dir qDebug() << " - Delete: "<<paths; - worker->pauseData = true; //pause any info requests + //worker->pauseData = true; //pause any info requests FODialog dlg(this); dlg.RemoveFiles(paths); dlg.show(); dlg.exec(); - worker->pauseData = false; //resume info requests - for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->refresh(); } + //worker->pauseData = false; //resume info requests + //for(int i=0; i<DWLIST.length(); i++){ DWLIST[i]->refresh(); } } void MainUI::CloseBrowser(QString ID){ @@ -959,3 +930,12 @@ void MainUI::CloseBrowser(QString ID){ OpenDirs(QStringList() << QDir::homePath()); } } + +void MainUI::TabNameChanged(QString id, QString name){ + for(int i=0; i<tabBar->count(); i++){ + if(tabBar->tabWhatsThis(i)==id){ + tabBar->setTabText(i, name); + return; + } + } +} diff --git a/src-qt5/desktop-utils/lumina-fm/MainUI.h b/src-qt5/desktop-utils/lumina-fm/MainUI.h index 19b40406..94c6f6c2 100644 --- a/src-qt5/desktop-utils/lumina-fm/MainUI.h +++ b/src-qt5/desktop-utils/lumina-fm/MainUI.h @@ -55,7 +55,7 @@ #include "DirData.h" #include "widgets/MultimediaWidget.h" #include "widgets/SlideshowWidget.h" -#include "widgets/DirWidget.h" +#include "widgets/DirWidget2.h" namespace Ui{ class MainUI; @@ -79,8 +79,8 @@ private: QTabBar *tabBar; //QFileSystemModel *fsmod; QMenu *contextMenu; - QRadioButton *radio_view_details, *radio_view_list, *radio_view_tabs, *radio_view_cols; - QWidgetAction *detWA, *listWA, *tabsWA, *colsWA; + QRadioButton *radio_view_details, *radio_view_list;//, *radio_view_tabs, *radio_view_cols; + QWidgetAction *detWA, *listWA;//, *tabsWA, *colsWA; //UI Widgets QList<DirWidget*> DWLIST; @@ -116,19 +116,19 @@ private slots: void on_actionSearch_triggered(); void on_actionClose_Browser_triggered(); void on_actionClose_triggered(); - void on_actionRename_triggered(); + /*void on_actionRename_triggered(); void on_actionCut_Selection_triggered(); void on_actionCopy_Selection_triggered(); void on_actionPaste_triggered(); - void on_actionDelete_Selection_triggered(); + void on_actionDelete_Selection_triggered();*/ void on_actionRefresh_triggered(); void on_actionView_Hidden_Files_triggered(); - void on_actionShow_Action_Buttons_triggered(); - void on_actionShow_Thumbnails_triggered(); + //void on_actionShow_Action_Buttons_triggered(); + //void on_actionShow_Thumbnails_triggered(); void goToBookmark(QAction*); void goToDevice(QAction*); void viewModeChanged(bool); - void groupModeChanged(bool); + //void groupModeChanged(bool); void on_actionLarger_Icons_triggered(); void on_actionSmaller_Icons_triggered(); void CreateBookMark(); @@ -148,7 +148,7 @@ private slots: void focusDirWidget(); //Backend Info passing - void DirDataAvailable(QString, QString, LFileInfoList); + //void DirDataAvailable(QString, QString, LFileInfoList); void SnapshotDataAvailable(QString, QString, QStringList); //Dir Browser Interactions @@ -162,7 +162,8 @@ private slots: void RenameFiles(QStringList); //file selection void RemoveFiles(QStringList); //file selection void CloseBrowser(QString); //ID - + void TabNameChanged(QString, QString); // ID/name + //file info in status bar void DisplayStatusBar(QString); diff --git a/src-qt5/desktop-utils/lumina-fm/MainUI.ui b/src-qt5/desktop-utils/lumina-fm/MainUI.ui index 3c11d87e..f356eadb 100644 --- a/src-qt5/desktop-utils/lumina-fm/MainUI.ui +++ b/src-qt5/desktop-utils/lumina-fm/MainUI.ui @@ -131,23 +131,11 @@ </property> <addaction name="actionTabs"/> </widget> - <widget class="QMenu" name="menuGroup_Mode"> - <property name="title"> - <string>Group Mode</string> - </property> - <addaction name="actionTabs_2"/> - </widget> <addaction name="actionRefresh"/> <addaction name="separator"/> - <addaction name="actionShow_Thumbnails"/> <addaction name="actionView_Hidden_Files"/> - <addaction name="actionShow_Action_Buttons"/> <addaction name="separator"/> <addaction name="menuView_Mode"/> - <addaction name="menuGroup_Mode"/> - <addaction name="separator"/> - <addaction name="actionLarger_Icons"/> - <addaction name="actionSmaller_Icons"/> </widget> <widget class="QMenu" name="menuBookmarks"> <property name="title"> @@ -164,18 +152,6 @@ <addaction name="actionScan"/> <addaction name="separator"/> </widget> - <widget class="QMenu" name="menuEdit"> - <property name="title"> - <string>Edit</string> - </property> - <addaction name="actionRename"/> - <addaction name="separator"/> - <addaction name="actionCut_Selection"/> - <addaction name="actionCopy_Selection"/> - <addaction name="actionPaste"/> - <addaction name="separator"/> - <addaction name="actionDelete_Selection"/> - </widget> <widget class="QMenu" name="menuGit"> <property name="title"> <string>Git</string> @@ -184,7 +160,6 @@ <addaction name="actionClone_Repository"/> </widget> <addaction name="menuFile"/> - <addaction name="menuEdit"/> <addaction name="menuView"/> <addaction name="menuBookmarks"/> <addaction name="menuExternal_Devices"/> @@ -193,7 +168,7 @@ <widget class="QStatusBar" name="statusbar"/> <action name="actionNew_Tab"> <property name="text"> - <string>New Browser</string> + <string>New Tab</string> </property> <property name="toolTip"> <string>New Browser</string> @@ -425,7 +400,7 @@ </action> <action name="actionClose_Browser"> <property name="text"> - <string>Close Browser</string> + <string>Close Tab</string> </property> <property name="shortcut"> <string>Ctrl+W</string> diff --git a/src-qt5/desktop-utils/lumina-fm/lumina-fm.pro b/src-qt5/desktop-utils/lumina-fm/lumina-fm.pro index 91e2952c..8fb482c7 100644 --- a/src-qt5/desktop-utils/lumina-fm/lumina-fm.pro +++ b/src-qt5/desktop-utils/lumina-fm/lumina-fm.pro @@ -15,9 +15,11 @@ SOURCES += main.cpp \ BMMDialog.cpp \ widgets/MultimediaWidget.cpp \ widgets/SlideshowWidget.cpp \ - widgets/DirWidget.cpp \ + widgets/DirWidget2.cpp \ gitCompat.cpp \ - gitWizard.cpp + gitWizard.cpp \ + Browser.cpp \ + BrowserWidget.cpp HEADERS += MainUI.h \ FODialog.h \ @@ -27,16 +29,18 @@ HEADERS += MainUI.h \ widgets/DDListWidgets.h \ widgets/MultimediaWidget.h \ widgets/SlideshowWidget.h \ - widgets/DirWidget.h \ + widgets/DirWidget2.h \ gitCompat.h \ - gitWizard.h + gitWizard.h \ + Browser.h \ + BrowserWidget.h FORMS += MainUI.ui \ FODialog.ui \ BMMDialog.ui \ widgets/MultimediaWidget.ui \ widgets/SlideshowWidget.ui \ - widgets/DirWidget.ui \ + widgets/DirWidget2.ui \ gitWizard.ui icons.files = Insight-FileManager.png diff --git a/src-qt5/desktop-utils/lumina-fm/main.cpp b/src-qt5/desktop-utils/lumina-fm/main.cpp index b05c4016..eaaf182c 100644 --- a/src-qt5/desktop-utils/lumina-fm/main.cpp +++ b/src-qt5/desktop-utils/lumina-fm/main.cpp @@ -9,6 +9,8 @@ #include <LuminaUtils.h> #include <LuminaSingleApplication.h> +#include "BrowserWidget.h" + int main(int argc, char ** argv) { LTHEME::LoadCustomEnvSettings(); @@ -28,6 +30,16 @@ int main(int argc, char ** argv) w.OpenDirs(in); w.show(); + // TESTING CODE FOR NEW BACKEND + /*QMainWindow W; + BrowserWidget B("",&W); + W.setCentralWidget( &B); + B.showDetails(false); + B.changeDirectory(in.first()); + qDebug() << "Show Window"; + W.show(); + */ + int retCode = a.exec(); return retCode; } diff --git a/src-qt5/desktop-utils/lumina-fm/widgets/DDListWidgets.h b/src-qt5/desktop-utils/lumina-fm/widgets/DDListWidgets.h index e3de9b0e..8049600e 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 <LuminaUtils.h> + //============== // LIST WIDGET //============== @@ -42,14 +44,20 @@ 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 } ~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; } @@ -155,8 +163,13 @@ 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; } @@ -237,4 +250,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 index d5f15a50..d729d608 100644 --- a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.cpp +++ b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.cpp @@ -181,7 +181,7 @@ QStringList DirWidget::getDateFormat() { void DirWidget::setDateFormat() { if(!date_format.isEmpty()) date_format.clear(); - QSettings settings("LuminaDE","sessionsettings"); + QSettings settings("lumina-desktop","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(); diff --git a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.h b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.h index afbb98cc..fecd6180 100644 --- a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.h +++ b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.h @@ -181,49 +181,4 @@ protected: }; -/* - * 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/DirWidget2.cpp b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.cpp new file mode 100644 index 00000000..cc608b92 --- /dev/null +++ b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.cpp @@ -0,0 +1,695 @@ +//=========================================== +// 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 <LuminaUtils.h> + +#include "../ScrollDialog.h" + +#define DEBUG 1 + +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(); + 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::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()) ); + cNewMenu->addAction(LXDG::findIcon("folder-new",""), tr("Directory"), this, SLOT(createNewDir()) ); + if(LUtils::isValidBinary("lumina-fileinfo")){ cNewMenu->addAction(LXDG::findIcon("system-run",""), tr("Application Launcher"), this, SLOT(createNewXDGEntry()) ); } + + 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())); + cOpenMenu->addAction(LXDG::findIcon("view-preview",""), tr("SlideShow"), this, SLOT(openInSlideshow())); + cOpenMenu->addAction(LXDG::findIcon("view-media-lyrics","media-playback-start"), tr("Multimedia Player"), this, SLOT(openMultimedia())); + + 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()) ); + cFModMenu->addAction(LXDG::findIcon("edit-copy",""), tr("Copy Selection"), this, SLOT(copyFiles()) ); + cFModMenu->addSeparator(); + cFModMenu->addAction(LXDG::findIcon("edit-rename",""), tr("Rename..."), this, SLOT(renameFiles()) ); + cFModMenu->addSeparator(); + cFModMenu->addAction(LXDG::findIcon("edit-delete",""), tr("Delete Selection"), this, SLOT(removeFiles()) ); + + 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:" << 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()) )->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{ 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); + }else{ + //Re-assemble the normalbasedir variable (in case moving around within a snapshot) + normalbasedir = cur.replace( QRegExp("/\\.zfs/snapshot/(.)+/"), "/" ); + } + 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){ + 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 = BW->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 = BW->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 = BW->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()){ return; } + emit CutFiles(sel); +} + +void DirWidget::copyFiles(){ + QStringList sel = currentBrowser()->currentSelection(); + if(sel.isEmpty()){ return; } + emit CopyFiles(sel); +} + +void DirWidget::pasteFiles(){ + emit PasteFiles(currentBrowser()->currentDirectory(), QStringList() ); +} + +void DirWidget::renameFiles(){ + QStringList sel = currentBrowser()->currentSelection(); + if(sel.isEmpty()){ 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()){ 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..6a9bdf79 --- /dev/null +++ b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.h @@ -0,0 +1,178 @@ +//=========================================== +// 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 + //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; + 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; + + //Functions for internal use + 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> |