aboutsummaryrefslogtreecommitdiff
path: root/src-qt5/desktop-utils/lumina-fm
diff options
context:
space:
mode:
authorWeblate <noreply@weblate.org>2016-10-03 12:09:26 +0000
committerWeblate <noreply@weblate.org>2016-10-03 12:09:26 +0000
commitf836ad04f629640db6c8076bf335d849eed64294 (patch)
treeeecfd74a4d7ba31489c8d76c70f900dacd1541d5 /src-qt5/desktop-utils/lumina-fm
parentTranslated using Weblate (l_FILEINFO@ja (generated)) (diff)
parentFix up some instability within lumina-fileinfo. (diff)
downloadlumina-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.cpp101
-rw-r--r--src-qt5/desktop-utils/lumina-fm/Browser.h29
-rw-r--r--src-qt5/desktop-utils/lumina-fm/BrowserWidget.cpp343
-rw-r--r--src-qt5/desktop-utils/lumina-fm/BrowserWidget.h101
-rw-r--r--src-qt5/desktop-utils/lumina-fm/DirData.h35
-rw-r--r--src-qt5/desktop-utils/lumina-fm/MainUI.cpp176
-rw-r--r--src-qt5/desktop-utils/lumina-fm/MainUI.h21
-rw-r--r--src-qt5/desktop-utils/lumina-fm/MainUI.ui29
-rw-r--r--src-qt5/desktop-utils/lumina-fm/lumina-fm.pro14
-rw-r--r--src-qt5/desktop-utils/lumina-fm/main.cpp12
-rw-r--r--src-qt5/desktop-utils/lumina-fm/widgets/DDListWidgets.h87
-rw-r--r--src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.cpp2
-rw-r--r--src-qt5/desktop-utils/lumina-fm/widgets/DirWidget.h45
-rw-r--r--src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.cpp695
-rw-r--r--src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.h178
-rw-r--r--src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.ui249
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>
bgstack15