aboutsummaryrefslogtreecommitdiff
path: root/src-qt5/desktop-utils/lumina-fm-dev/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'src-qt5/desktop-utils/lumina-fm-dev/widgets')
-rw-r--r--src-qt5/desktop-utils/lumina-fm-dev/widgets/DDListWidgets.h329
-rw-r--r--src-qt5/desktop-utils/lumina-fm-dev/widgets/DirWidget2.cpp907
-rw-r--r--src-qt5/desktop-utils/lumina-fm-dev/widgets/DirWidget2.h193
-rw-r--r--src-qt5/desktop-utils/lumina-fm-dev/widgets/DirWidget2.ui261
-rw-r--r--src-qt5/desktop-utils/lumina-fm-dev/widgets/MultimediaWidget.cpp222
-rw-r--r--src-qt5/desktop-utils/lumina-fm-dev/widgets/MultimediaWidget.h71
-rw-r--r--src-qt5/desktop-utils/lumina-fm-dev/widgets/MultimediaWidget.ui181
-rw-r--r--src-qt5/desktop-utils/lumina-fm-dev/widgets/SlideshowWidget.cpp169
-rw-r--r--src-qt5/desktop-utils/lumina-fm-dev/widgets/SlideshowWidget.h57
-rw-r--r--src-qt5/desktop-utils/lumina-fm-dev/widgets/SlideshowWidget.ui346
10 files changed, 2736 insertions, 0 deletions
diff --git a/src-qt5/desktop-utils/lumina-fm-dev/widgets/DDListWidgets.h b/src-qt5/desktop-utils/lumina-fm-dev/widgets/DDListWidgets.h
new file mode 100644
index 00000000..254362fd
--- /dev/null
+++ b/src-qt5/desktop-utils/lumina-fm-dev/widgets/DDListWidgets.h
@@ -0,0 +1,329 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This is a couple simple widget subclasses to enable drag and drop functionality
+// NOTE: The "whatsThis()" item information needs to correspond to the "[cut/copy]::::<file path>" syntax
+//NOTE2: The "whatsThis()" information on the widget itself should be the current dir path *if* it can accept drops
+//===========================================
+#ifndef _LUMINA_FM_DRAG_DROP_WIDGETS_H
+#define _LUMINA_FM_DRAG_DROP_WIDGETS_H
+
+#define MIME QString("x-special/lumina-copied-files")
+
+#include <QListWidget>
+#include <QTreeWidget>
+#include <QDropEvent>
+#include <QMimeData>
+#include <QDrag>
+#include <QFileInfo>
+#include <QDebug>
+#include <QMouseEvent>
+#include <QUrl>
+#include <QDir>
+
+#include <LUtils.h>
+
+//==============
+// LIST WIDGET
+//==============
+class DDListWidget : public QListWidget{
+ Q_OBJECT
+public:
+ DDListWidget(QWidget *parent=0) : QListWidget(parent){
+ //Drag and Drop Properties
+ this->setDragDropMode(QAbstractItemView::DragDrop);
+ this->setDefaultDropAction(Qt::MoveAction); //prevent any built-in Qt actions - the class handles it
+ //Other custom properties necessary for the FM
+ this->setFocusPolicy(Qt::StrongFocus);
+ this->setContextMenuPolicy(Qt::CustomContextMenu);
+ this->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ this->setSelectionBehavior(QAbstractItemView::SelectRows);
+ this->setFlow(QListView::TopToBottom);
+ this->setWrapping(true);
+ this->setMouseTracking(true);
+ this->setSortingEnabled(true); //This sorts *only* by name - type is not preserved
+ //this->setStyleSheet("QListWidget::item{ border: 1px solid transparent; border-radius: 5px; background-color: transparent;} QListWidget::item:hover{ border-color: black; } QListWidget::item:focus{ border-color: lightblue; }");
+ }
+ ~DDListWidget(){}
+
+signals:
+ void DataDropped(QString, QStringList); //Dir path, List of commands
+ void GotFocus();
+
+protected:
+ void focusInEvent(QFocusEvent *ev){
+ QListWidget::focusInEvent(ev);
+ emit GotFocus();
+ }
+
+ void startDrag(Qt::DropActions act){
+ QList<QListWidgetItem*> items = this->selectedItems();
+ if(items.length()<1){ return; }
+ QList<QUrl> urilist;
+ for(int i=0; i<items.length(); i++){
+ urilist << QUrl::fromLocalFile(items[i]->whatsThis());
+ }
+ //Create the mime data
+ //qDebug() << "Start Drag:" << urilist;
+ QMimeData *mime = new QMimeData;
+ mime->setUrls(urilist);
+ //Create the drag structure
+ QDrag *drag = new QDrag(this);
+ drag->setMimeData(mime);
+ /*if(info.first().section("::::",0,0)=="cut"){
+ drag->exec(act | Qt::MoveAction);
+ }else{*/
+ drag->exec(act | Qt::CopyAction);
+ //}
+ }
+
+ void dragEnterEvent(QDragEnterEvent *ev){
+ //qDebug() << "Drag Enter Event:" << ev->mimeData()->hasFormat(MIME);
+ if(ev->mimeData()->hasUrls() && !this->whatsThis().isEmpty() ){
+ ev->acceptProposedAction(); //allow this to be dropped here
+ }else{
+ ev->ignore();
+ }
+ }
+
+ void dragMoveEvent(QDragMoveEvent *ev){
+ if(ev->mimeData()->hasUrls() && !this->whatsThis().isEmpty() ){
+ //Change the drop type depending on the data/dir
+ QString home = QDir::homePath();
+ //qDebug() << "Drag Move:" << home << this->whatsThis();
+ if( this->whatsThis().startsWith(home) ){ ev->setDropAction(Qt::MoveAction); this->setCursor(Qt::DragMoveCursor); }
+ else{ ev->setDropAction(Qt::CopyAction); this->setCursor(Qt::DragCopyCursor);}
+ ev->acceptProposedAction(); //allow this to be dropped here
+ //this->setCursor(Qt::CrossCursor);
+ }else{
+ this->setCursor(Qt::ForbiddenCursor);
+ ev->ignore();
+ }
+ this->update();
+ }
+
+ void dropEvent(QDropEvent *ev){
+ if(this->whatsThis().isEmpty() || !ev->mimeData()->hasUrls() ){ ev->ignore(); return; } //not supported
+ //qDebug() << "Drop Event:";
+ ev->accept(); //handled here
+ QString dirpath = this->whatsThis();
+ //See if the item under the drop point is a directory or not
+ QListWidgetItem *it = this->itemAt( ev->pos());
+ if(it!=0){
+ //qDebug() << "Drop Item:" << it->whatsThis();
+ QFileInfo info(it->whatsThis());
+ if(info.isDir() && info.isWritable()){
+ dirpath = info.absoluteFilePath();
+ }
+ }
+ //Now turn the input urls into local file paths
+ QStringList files;
+ QString home = QDir::homePath();
+ foreach(const QUrl &url, ev->mimeData()->urls()){
+ const QString filepath = url.toLocalFile();
+ //If the target file is modifiable, assume a move - otherwise copy
+ if(QFileInfo(filepath).isWritable() && (filepath.startsWith(home) && dirpath.startsWith(home))){
+ if(filepath.section("/",0,-2)!=dirpath){ files << "cut::::"+filepath; } //don't "cut" a file into the same dir
+ }else{ files << "copy::::"+filepath; }
+ }
+ //qDebug() << "Drop Event:" << dirpath << files;
+ if(!files.isEmpty()){ emit DataDropped( dirpath, files ); }
+ this->setCursor(Qt::ArrowCursor);
+ }
+
+ void mouseReleaseEvent(QMouseEvent *ev){
+ if(ev->button() != Qt::RightButton && ev->button() != Qt::LeftButton){ ev->ignore(); }
+ else{ QListWidget::mouseReleaseEvent(ev); } //pass it along to the widget
+ }
+ void mousePressEvent(QMouseEvent *ev){
+ if(ev->button() != Qt::RightButton && ev->button() != Qt::LeftButton){ ev->ignore(); }
+ else{ QListWidget::mousePressEvent(ev); } //pass it along to the widget
+ }
+ /*void mouseMoveEvent(QMouseEvent *ev){
+ if(ev->button() != Qt::RightButton && ev->button() != Qt::LeftButton){ ev->ignore(); }
+ else{ QListWidget::mouseMoveEvent(ev); } //pass it along to the widget
+ }*/
+};
+
+//================
+// TreeWidget
+//================
+class DDTreeWidget : public QTreeWidget{
+ Q_OBJECT
+public:
+ DDTreeWidget(QWidget *parent=0) : QTreeWidget(parent){
+ //Drag and Drop Properties
+ this->setDragDropMode(QAbstractItemView::DragDrop);
+ this->setDefaultDropAction(Qt::MoveAction); //prevent any built-in Qt actions - the class handles it
+ //Other custom properties necessary for the FM
+ this->setFocusPolicy(Qt::StrongFocus);
+ this->setContextMenuPolicy(Qt::CustomContextMenu);
+ this->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ this->setSelectionBehavior(QAbstractItemView::SelectRows);
+ this->setMouseTracking(true);
+ this->setSortingEnabled(true);
+ this->setIndentation(0);
+ this->setItemsExpandable(false);
+ }
+ ~DDTreeWidget(){}
+
+signals:
+ void DataDropped(QString, QStringList); //Dir path, List of commands
+ void GotFocus();
+
+protected:
+ void focusInEvent(QFocusEvent *ev){
+ QTreeWidget::focusInEvent(ev);
+ emit GotFocus();
+ }
+ void startDrag(Qt::DropActions act){
+ QList<QTreeWidgetItem*> items = this->selectedItems();
+ if(items.length()<1){ return; }
+ QList<QUrl> urilist;
+ for(int i=0; i<items.length(); i++){
+ urilist << QUrl::fromLocalFile(items[i]->whatsThis(0));
+ }
+ //Create the mime data
+ QMimeData *mime = new QMimeData;
+ mime->setUrls(urilist);
+ //Create the drag structure
+ QDrag *drag = new QDrag(this);
+ drag->setMimeData(mime);
+ /*if(info.first().section("::::",0,0)=="cut"){
+ drag->exec(act | Qt::MoveAction);
+ }else{*/
+ drag->exec(act | Qt::CopyAction| Qt::MoveAction);
+ //}
+ }
+
+ void dragEnterEvent(QDragEnterEvent *ev){
+ //qDebug() << "Drag Enter Event:" << ev->mimeData()->hasFormat(MIME);
+ if(ev->mimeData()->hasUrls() && !this->whatsThis().isEmpty() ){
+ ev->acceptProposedAction(); //allow this to be dropped here
+ }else{
+ ev->ignore();
+ }
+ }
+
+ void dragMoveEvent(QDragMoveEvent *ev){
+ if(ev->mimeData()->hasUrls() && !this->whatsThis().isEmpty() ){
+ //Change the drop type depending on the data/dir
+ QString home = QDir::homePath();
+ if( this->whatsThis().startsWith(home) ){ ev->setDropAction(Qt::MoveAction); }
+ else{ ev->setDropAction(Qt::CopyAction); }
+ ev->accept(); //allow this to be dropped here
+ }else{
+ ev->ignore();
+ }
+ }
+
+ void dropEvent(QDropEvent *ev){
+ if(this->whatsThis().isEmpty() || !ev->mimeData()->hasUrls() ){ ev->ignore(); return; } //not supported
+ ev->accept(); //handled here
+ QString dirpath = this->whatsThis();
+ //See if the item under the drop point is a directory or not
+ QTreeWidgetItem *it = this->itemAt( ev->pos());
+ if(it!=0){
+ QFileInfo info(it->whatsThis(0));
+ if(info.isDir() && info.isWritable()){
+ dirpath = info.absoluteFilePath();
+ }
+ }
+ //qDebug() << "Drop Event:" << dirpath;
+ //Now turn the input urls into local file paths
+ QStringList files;
+ QString home = QDir::homePath();
+ foreach(const QUrl &url, ev->mimeData()->urls()){
+ const QString filepath = url.toLocalFile();
+ //If the target file is modifiable, assume a move - otherwise copy
+ if(QFileInfo(filepath).isWritable() && (filepath.startsWith(home) && dirpath.startsWith(home))){
+ if(filepath.section("/",0,-2)!=dirpath){ files << "cut::::"+filepath; } //don't "cut" a file into the same dir
+ }else{ files << "copy::::"+filepath; }
+ }
+ //qDebug() << "Drop Event:" << dirpath;
+ emit DataDropped( dirpath, files );
+ }
+
+ void mouseReleaseEvent(QMouseEvent *ev){
+ if(ev->button() != Qt::RightButton && ev->button() != Qt::LeftButton){ ev->ignore(); }
+ else{ QTreeWidget::mouseReleaseEvent(ev); } //pass it along to the widget
+ }
+ void mousePressEvent(QMouseEvent *ev){
+ if(ev->button() != Qt::RightButton && ev->button() != Qt::LeftButton){ ev->ignore(); }
+ else{ QTreeWidget::mousePressEvent(ev); } //pass it along to the widget
+ }
+ /*void mouseMoveEvent(QMouseEvent *ev){
+ if(ev->button() != Qt::RightButton && ev->button() != Qt::LeftButton){ ev->ignore(); }
+ else{ QTreeWidget::mouseMoveEvent(ev); } //pass it along to the widget
+ }*/
+};
+
+/*
+ * 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-dev/widgets/DirWidget2.cpp b/src-qt5/desktop-utils/lumina-fm-dev/widgets/DirWidget2.cpp
new file mode 100644
index 00000000..3790d145
--- /dev/null
+++ b/src-qt5/desktop-utils/lumina-fm-dev/widgets/DirWidget2.cpp
@@ -0,0 +1,907 @@
+//===========================================
+// 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 <QActionGroup>
+#include <QMessageBox>
+#include <QCursor>
+#include <QClipboard>
+#include <QMimeData>
+#include <QTimer>
+#include <QInputDialog>
+#include <QScrollBar>
+#include <QSettings>
+#include <QtConcurrent>
+#include <QFileSystemModel>
+#include <QCompleter>
+#include <LuminaOS.h>
+#include <LuminaXDG.h>
+#include <LUtils.h>
+#include <ExternalProcess.h>
+
+#include "../ScrollDialog.h"
+
+#define DEBUG 0
+
+DirWidget::DirWidget(QString objID, QWidget *parent) : QWidget(parent), ui(new Ui::DirWidget){
+ ui->setupUi(this); //load the designer file
+ ID = objID;
+ //Assemble the toolbar for the widget
+ toolbar = new QToolBar(this);
+ toolbar->setContextMenuPolicy(Qt::CustomContextMenu);
+ toolbar->setFloatable(false);
+ toolbar->setMovable(false);
+ toolbar->setOrientation(Qt::Horizontal);
+ toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly);
+ //toolbar->setIconSize(QSize(32,32));
+ ui->toolbar_layout->addWidget(toolbar);
+ // - Add the buttons to the toolbar
+ toolbar->addAction(ui->actionBack);
+ toolbar->addAction(ui->actionUp);
+ toolbar->addAction(ui->actionHome);
+ line_dir = new QLineEdit(this);
+ toolbar->addWidget(line_dir);
+ connect(line_dir, SIGNAL(returnPressed()), this, SLOT(dir_changed()) );
+ QActionGroup *columnActionGroup = new QActionGroup(this);
+ toolbar->addAction(ui->actionSingleColumn);
+ ui->actionSingleColumn->setChecked(true);
+ columnActionGroup->addAction(ui->actionSingleColumn);
+ toolbar->addAction(ui->actionDualColumn);
+ columnActionGroup->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)) );
+
+ // Create treeviewpane QFileSystemModel model and populate
+ QString folderTreePath = QDir::rootPath();
+ dirtreeModel = new QFileSystemModel(this);
+ dirtreeModel->setFilter(QDir::NoDotAndDotDot | QDir::AllDirs); // remove extraneous dirs
+ dirtreeModel->setRootPath(folderTreePath);
+ ui->folderViewPane->setModel(dirtreeModel);
+ ui->splitter->setSizes( QList<int>() << this->width()/4 << 3*this->width()/4);
+ ui->folderViewPane->setHeaderHidden(true);
+ ui->folderViewPane->resizeColumnToContents(0);
+ ui->folderViewPane->setColumnHidden(1, true);
+ ui->folderViewPane->setColumnHidden(2, true);
+ ui->folderViewPane->setColumnHidden(3, true);
+
+ //Now update the rest of the UI
+ canmodify = false; //initial value
+ contextMenu = new QMenu(this);
+ cNewMenu = cOpenMenu = cFModMenu = cFViewMenu = cOpenWithMenu = 0; //not created yet
+ connect(contextMenu, SIGNAL(aboutToShow()), this, SLOT(UpdateContextMenu()) );
+ connect(ui->splitter, SIGNAL(splitterMoved(int,int)), this, SLOT(splitterMoved()) );
+
+ UpdateIcons();
+ UpdateText();
+ createShortcuts();
+ createMenus();
+ line_dir->setCompleter(new QCompleter(dirtreeModel, this));
+}
+
+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); }
+ //Also make sure the tree model is showing hidden files as needed
+ if(show){ dirtreeModel->setFilter(QDir::NoDotAndDotDot | QDir::Hidden | QDir::AllDirs); }
+ else{ dirtreeModel->setFilter(QDir::NoDotAndDotDot | QDir::AllDirs); }
+}
+
+void DirWidget::showThumbnails(bool show){
+ BW->showThumbnails(show);
+ if(RCBW!=0){ RCBW->showThumbnails(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
+}
+
+//====================
+// Folder Pane
+//====================
+void DirWidget::adjustTreeWidget(float percent){
+ ui->splitter->setSizes( QList<int>() << this->width()*(percent/100.0) << this->width() * ((100.0-percent)/100.0) );
+}
+
+void DirWidget::on_folderViewPane_clicked(const QModelIndex &index){
+ QString tPath = dirtreeModel->fileInfo(index).absoluteFilePath(); // get what was clicked
+ ChangeDir(tPath);
+}
+
+// ================
+// 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("view-more-vertical","format-list-unordered") );
+ ui->actionSingleColumn->setIcon(LXDG::findIcon("view-right-close","view-close") );
+ ui->actionDualColumn->setIcon(LXDG::findIcon("view-right-new","view-split-left-right") );
+
+ ui->tool_zoom_in->setIcon(LXDG::findIcon("zoom-in",""));
+ ui->tool_zoom_out->setIcon(LXDG::findIcon("zoom-out",""));
+}
+
+void DirWidget::UpdateText(){
+ ui->retranslateUi(this);
+ BW->retranslate();
+ if(RCBW!=0){ RCBW->retranslate(); }
+}
+
+// =================
+// PRIVATE
+// =================
+void DirWidget::createShortcuts(){
+ kZoomIn= new QShortcut(QKeySequence(QKeySequence::ZoomIn),this);
+ kZoomOut= new QShortcut(QKeySequence(QKeySequence::ZoomOut),this);
+ kNewFile= new QShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_F),this);
+ kNewDir= new QShortcut(QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_N),this);
+ kNewXDG= new QShortcut(QKeySequence(Qt::CTRL+Qt::Key_G),this);
+ kCut= new QShortcut(QKeySequence(QKeySequence::Cut),this);
+ kCopy= new QShortcut(QKeySequence(QKeySequence::Copy),this);
+ kPaste= new QShortcut(QKeySequence(QKeySequence::Paste),this);
+ kRename= new QShortcut(QKeySequence(Qt::Key_F2),this);
+ kExtract= new QShortcut(QKeySequence(Qt::CTRL+Qt::Key_E), this);
+ kFav= new QShortcut(QKeySequence(Qt::Key_F3),this);
+ kDel= new QShortcut(QKeySequence(QKeySequence::Delete),this);
+ kOpSS= new QShortcut(QKeySequence(Qt::Key_F6),this);
+ kOpMM= new QShortcut(QKeySequence(Qt::Key_F7),this);
+ kOpTerm = new QShortcut(QKeySequence(Qt::Key_F1),this);
+
+ connect(kZoomIn, SIGNAL(activated()), this, SLOT(on_tool_zoom_in_clicked()) );
+ connect(kZoomOut, SIGNAL(activated()), this, SLOT(on_tool_zoom_out_clicked()) );
+ connect(kNewFile, SIGNAL(activated()), this, SLOT(createNewFile()) );
+ connect(kNewDir, SIGNAL(activated()), this, SLOT(createNewDir()) );
+ connect(kNewXDG, SIGNAL(activated()), this, SLOT(createNewXDGEntry()) );
+ connect(kCut, SIGNAL(activated()), this, SLOT(cutFiles()) );
+ connect(kCopy, SIGNAL(activated()), this, SLOT(copyFiles()) );
+ connect(kPaste, SIGNAL(activated()), this, SLOT(pasteFiles()) );
+ connect(kRename, SIGNAL(activated()), this, SLOT(renameFiles()) );
+ connect(kExtract, SIGNAL(activated()), this, SLOT(autoExtractFiles()) );
+ connect(kFav, SIGNAL(activated()), this, SLOT(favoriteFiles()) );
+ connect(kDel, SIGNAL(activated()), this, SLOT(removeFiles()) );
+ connect(kOpSS, SIGNAL(activated()), this, SLOT(openInSlideshow()) );
+ connect(kOpMM, SIGNAL(activated()), this, SLOT(openMultimedia()) );
+ connect(kOpTerm, SIGNAL(activated()), this, SLOT(openTerminal()) );
+}
+
+void DirWidget::createMenus(){
+ //Note: contextMenu already created - this is just for the sub-items
+ if(cNewMenu==0){ cNewMenu = new QMenu(this); }
+ else{ cNewMenu->clear(); }
+ cNewMenu->setTitle(tr("Create...") );
+ cNewMenu->setIcon( LXDG::findIcon("list-add","") );
+ cNewMenu->addAction(LXDG::findIcon("document-new",""), tr("File"), this, SLOT(createNewFile()), kNewFile->key() );
+ cNewMenu->addAction(LXDG::findIcon("folder-new",""), tr("Directory"), this, SLOT(createNewDir()), kNewDir->key() );
+ if(LUtils::isValidBinary("lumina-fileinfo")){ cNewMenu->addAction(LXDG::findIcon("system-run",""), tr("Application Launcher"), this, SLOT(createNewXDGEntry()), kNewXDG->key() ); }
+
+ if(cOpenMenu==0){ cOpenMenu = new QMenu(this); }
+ else{ cOpenMenu->clear(); }
+ cOpenMenu->setTitle(tr("Launch..."));
+ cOpenMenu->setIcon( LXDG::findIcon("quickopen","") );
+ cOpenMenu->addAction(LXDG::findIcon("utilities-terminal",""), tr("Terminal"), this, SLOT(openTerminal()), kOpTerm->key());
+ cOpenMenu->addAction(LXDG::findIcon("media-slideshow",""), tr("SlideShow"), this, SLOT(openInSlideshow()), kOpSS->key());
+ cOpenMenu->addAction(LXDG::findIcon("media-playback-start-circled","media-playback-start"), tr("Multimedia Player"), this, SLOT(openMultimedia()), kOpMM->key());
+/*
+ if(cFModMenu==0){ cFModMenu = new QMenu(this); }
+ else{ cFModMenu->clear(); }
+ cFModMenu->setTitle(tr("Modify Files..."));
+ cFModMenu->setIcon( LXDG::findIcon("document-edit","") );
+ cFModMenu->addAction(LXDG::findIcon("edit-cut",""), tr("Cut Selection"), this, SLOT(cutFiles()), kCut->key() );
+ cFModMenu->addAction(LXDG::findIcon("edit-copy",""), tr("Copy Selection"), this, SLOT(copyFiles()), kCopy->key() );
+ cFModMenu->addSeparator();
+ cFModMenu->addAction(LXDG::findIcon("edit-rename",""), tr("Rename..."), this, SLOT(renameFiles()), kRename->key() );
+ cFModMenu->addSeparator();
+ cFModMenu->addAction(LXDG::findIcon("edit-delete",""), tr("Delete Selection"), this, SLOT(removeFiles()), kDel->key() );
+*/
+
+//---------------------------------------------------//
+
+ if(cOpenWithMenu==0){
+ cOpenWithMenu = new QMenu(this);
+ connect(cOpenWithMenu, SIGNAL(triggered(QAction*)), this, SLOT(OpenWithApp(QAction*)) );
+ }
+ else{ cOpenWithMenu->clear(); }
+ cOpenWithMenu->setTitle(tr("Open with..."));
+ cOpenWithMenu->setIcon( LXDG::findIcon("system-run-with","") );
+
+//---------------------------------------------------//
+ 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
+// =================
+void DirWidget::splitterMoved(){
+ float percent = (ui->splitter->sizes().first() / ( (float) this->width()) )*100.0;
+ this->emit treeWidgetSizeChanged(percent);
+}
+
+//UI BUTTONS
+void DirWidget::on_tool_zoom_in_clicked(){
+ int size = BW->thumbnailSize();
+ size += 16;
+ setThumbnailSize(size);
+ //Now Save the size value as the default for next time
+ QSettings SET("lumina-desktop","lumina-fm");
+ SET.setValue("iconsize", size);
+}
+
+void DirWidget::on_tool_zoom_out_clicked(){
+ int size = BW->thumbnailSize();
+ if(size <= 16){ return; }
+ size -= 16;
+ setThumbnailSize(size);
+ //Now Save the size value as the default for next time
+ QSettings SET("lumina-desktop","lumina-fm");
+ SET.setValue("iconsize", size);
+}
+
+// -- Top Snapshot Buttons
+void DirWidget::on_tool_snap_newer_clicked(){
+ ui->slider_snap->setValue( ui->slider_snap->value()+1 );
+}
+
+void DirWidget::on_tool_snap_older_clicked(){
+ ui->slider_snap->setValue( ui->slider_snap->value()-1 );
+}
+
+void DirWidget::on_slider_snap_valueChanged(int val){
+ bool labelsonly = false;
+ if(val==-1){ val = ui->slider_snap->value(); labelsonly=true; }
+ //Update the snapshot interface
+ ui->tool_snap_newer->setEnabled(val < ui->slider_snap->maximum());
+ ui->tool_snap_older->setEnabled(val > ui->slider_snap->minimum());
+ if(val >= snapshots.length() || val < 0){
+ ui->tool_snap->setText(tr("Current"));
+ }else if(QFile::exists(snapbasedir+snapshots[val])){
+ ui->tool_snap->setText( QFileInfo(snapbasedir+snapshots[val]).lastModified().toString(Qt::DefaultLocaleShortDate) );
+ }
+ //Exit if a non-interactive snapshot change
+ if(!ui->group_snaps->isEnabled() || labelsonly){ return; } //internal change - do not try to change the actual info
+ //Determine which snapshot is now selected
+ QString dir;
+ if(DEBUG){ qDebug() << "Changing snapshot:" << currentBrowser()->currentDirectory() << val << snapbasedir; }
+ //stopload = true; //stop any currently-loading procedures
+ if(val >= snapshots.length() || val < 0){ //active system selected
+ if(DEBUG){ qDebug() << " - Load Active system:" << normalbasedir; }
+ dir = normalbasedir;
+ }else{
+ dir = snapbasedir+snapshots[val]+"/";
+ if(!QFile::exists(dir)){
+ //This snapshot must have been removed in the background by pruning tools
+ // move to a newer snapshot or the current base dir as necessary
+ qDebug() << "Snapshot no longer available:" << dir;
+ qDebug() << " - Reloading available snapshots";
+ emit findSnaps(ID, normalbasedir);
+ return;
+ }
+ //Need to figure out the relative path within the snapshot
+ snaprelpath = normalbasedir.section(snapbasedir.section(ZSNAPDIR,0,0), 1,1000);
+ if(DEBUG){ qDebug() << " - new snapshot-relative path:" << snaprelpath; }
+ dir.append(snaprelpath);
+ dir.replace("//","/"); //just in case any duplicate slashes from all the split/combining
+ if(DEBUG){ qDebug() << " - Load Snapshot:" << dir; }
+ }
+ //Make sure this directory exists, and back up as necessary
+ if(dir.isEmpty()){ return; }
+ //Load the newly selected snapshot
+ currentBrowser()->changeDirectory(dir);
+}
+
+void DirWidget::direct_snap_selected(QAction *act){
+ QString snap = act->whatsThis();
+ int val = snapshots.indexOf(snap);
+ if(val<0){ return; }
+ else{ ui->slider_snap->setValue(val); }
+}
+
+//Top Toolbar buttons
+void DirWidget::on_actionBack_triggered(){
+ QStringList history = currentBrowser()->history();
+ if(history.length()<2){ return; } //cannot do anything
+ QString dir = history.takeLast();
+ //qDebug() << "Go Back:" << dir << normalbasedir << history;
+ if(dir == normalbasedir){
+ dir = history.takeLast();
+ }
+ history << dir; //make sure the current dir is always last in the history
+ currentBrowser()->changeDirectory(dir);
+ currentBrowser()->setHistory(history); //re-write the history to account for going backwards
+ ui->actionBack->setEnabled(history.length()>1);
+}
+
+void DirWidget::on_actionUp_triggered(){
+QString dir = currentBrowser()->currentDirectory().section("/",0,-2);
+ if(dir.isEmpty())
+ dir = "/";
+ //Quick check to ensure the directory exists
+ while(!QFile::exists(dir) && !dir.isEmpty()){
+ dir = dir.section("/",0,-2); //back up one additional dir
+ }
+ currentBrowser()->changeDirectory(dir);
+}
+
+void DirWidget::on_actionHome_triggered(){
+ currentBrowser()->changeDirectory(QDir::homePath());
+}
+
+void DirWidget::dir_changed(){
+ QString dir = line_dir->text().simplified();
+ //Run the dir through the user-input checks
+ dir = LUtils::PathToAbsolute(dir);
+ //qDebug() << "Dir Changed:" << dir;
+ //Quick check to ensure the directory exists
+ while(!QFile::exists(dir) && !dir.isEmpty()){
+ dir = dir.section("/",0,-2); //back up one additional dir
+ }
+ //qDebug() << " - Now Dir:" << dir;
+ currentBrowser()->changeDirectory(dir);
+ //emit LoadDirectory(ID, dir);
+}
+
+
+void DirWidget::on_actionSingleColumn_triggered(bool checked){
+ if(!checked){ return; }
+ 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; }
+ 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
+ QStringList sel = currentBrowser()->currentSelection();
+ //qDebug() << "Update context menu";
+ //qDebug() << " Selection:" << sel;
+ contextMenu->clear();
+
+ if(!sel.isEmpty()){
+ contextMenu->addAction(LXDG::findIcon("system-run",""), tr("Open"), this, SLOT(runFiles()) );
+ //contextMenu->addAction(LXDG::findIcon("system-run-with",""), tr("Open With..."), this, SLOT(runWithFiles()) );
+ contextMenu->addMenu(cOpenWithMenu);
+ }
+ contextMenu->addSection(LXDG::findIcon("unknown",""), tr("File Operations"));
+ // contextMenu->addMenu(cFModMenu);
+ // cFModMenu->setEnabled(!sel.isEmpty() && canmodify);
+
+ if(!sel.isEmpty()){
+ contextMenu->addAction(LXDG::findIcon("edit-rename",""), tr("Rename..."), this, SLOT(renameFiles()), kRename->key() )->setEnabled(canmodify);
+ contextMenu->addAction(LXDG::findIcon("edit-cut",""), tr("Cut Selection"), this, SLOT(cutFiles()), kCut->key() )->setEnabled(canmodify);
+ contextMenu->addAction(LXDG::findIcon("edit-copy",""), tr("Copy Selection"), this, SLOT(copyFiles()), kCopy->key() )->setEnabled(canmodify);
+ if(LUtils::isValidBinary("lumina-archiver") && sel.length() ==1){ contextMenu->addAction(LXDG::findIcon("archive",""), tr("Auto-Extract"), this, SLOT(autoExtractFiles()), kExtract->key() )->setEnabled(canmodify); }
+ }
+ if( QApplication::clipboard()->mimeData()->hasFormat("x-special/lumina-copied-files") ){
+ contextMenu->addAction(LXDG::findIcon("edit-paste",""), tr("Paste"), this, SLOT(pasteFiles()), QKeySequence(Qt::CTRL+Qt::Key_V) )->setEnabled(canmodify);
+ }
+ if(!sel.isEmpty()){
+ contextMenu->addSeparator();
+ contextMenu->addAction(LXDG::findIcon("edit-delete",""), tr("Delete Selection"), this, SLOT(removeFiles()), kDel->key() )->setEnabled(canmodify);
+ contextMenu->addSeparator();
+ }
+ contextMenu->addMenu(cFViewMenu);
+ cFViewMenu->setEnabled(!sel.isEmpty());
+
+ //Now add the general selection options
+ contextMenu->addSection(LXDG::findIcon("folder","inode/directory"), tr("Directory Operations"));
+ if(canmodify){
+ contextMenu->addMenu(cNewMenu);
+ }
+ contextMenu->addMenu(cOpenMenu);
+ //=====================
+ //PREFAPPS = getPreferredApplications();
+ //qDebug() << "Preferred Apps:" << PREFAPPS;
+ cOpenWithMenu->clear();
+ //Now get the application mimetype for the file extension (if available)
+ QStringList mimetypes;
+ for(int i=0; i<sel.length(); i++){
+ QStringList mimes = LXDG::findAppMimeForFile(sel[i], true).split("::::"); //use all mimetypes
+ if(mimetypes.isEmpty()){ mimetypes << mimes; }
+ else{
+ //need to verify that the mimetypes are the same before adding them.
+ QStringList test; test << mimetypes << mimes;
+ if(test.removeDuplicates()>0){ mimetypes = test; }
+ else{
+ //Bad match - incompatible file types are selected - disable the recommendations
+ mimetypes.clear();
+ break;
+ }
+ }
+ }
+ //Now add all the detected applications
+ if(!mimetypes.isEmpty()){
+ static XDGDesktopList applist;
+ applist.updateList();
+ QList<XDGDesktop*> apps = applist.apps(false,true);
+ QList<XDGDesktop*> found;
+ for(int a=0; a<apps.length(); a++){
+ if(apps[a]->mimeList.isEmpty()){ continue; } //no corresponding mime types for this app
+ QStringList test; test << mimetypes << apps[a]->mimeList;
+ if(test.removeDuplicates()>0){ found << apps[a]; }
+ }
+ if(!found.isEmpty()){
+ //sort the apps by name
+ found = LXDG::sortDesktopNames(found);
+ //add apps to the menu
+ for(int i=0; i<found.length(); i++){
+ QAction *act = cOpenWithMenu->addAction( LXDG::findIcon(found[i]->icon, ""), found[i]->name );
+ act->setToolTip(found[i]->comment);
+ act->setWhatsThis(found[i]->filePath);
+ }
+ cOpenWithMenu->addSeparator();
+ }
+ }
+ cOpenWithMenu->addAction(LXDG::findIcon("system-run-with",""), tr("Other..."), this, SLOT(runWithFiles()) );
+}
+
+void DirWidget::currentDirectoryChanged(bool widgetonly){
+ QString cur = currentBrowser()->currentDirectory();
+ QFileInfo info(cur);
+ canmodify = info.isWritable();
+ if(widgetonly){ ui->label_status->setText(currentBrowser()->status()); }
+ else if( !currentBrowser()->isEnabled() ){ ui->label_status->setText(tr("Loading...")); }
+ //qDebug() << "Start search for snapshots";
+ if(!cur.contains("/.zfs/snapshot") ){
+ normalbasedir = cur;
+ ui->group_snaps->setVisible(false);
+ emit findSnaps(ID, cur);
+ //qDebug() << "Changed to directory:" << cur;
+ }else{
+ //Re-assemble the normalbasedir variable (in case moving around within a snapshot)
+ normalbasedir = cur;
+ normalbasedir.replace( QRegExp("\\/\\.zfs\\/snapshot/([^/]+)\\/"), "/" );
+ //qDebug() << "Changed to snapshot:" << cur << normalbasedir;
+ }
+ ui->actionBack->setEnabled( currentBrowser()->history().length()>1 );
+ line_dir->setText(normalbasedir);
+ emit TabNameChanged(ID, normalbasedir.section("/",-1));
+ QModelIndex index = dirtreeModel->index(normalbasedir,0);
+ ui->folderViewPane->setCurrentIndex( index );
+ ui->folderViewPane->scrollTo(index);
+}
+
+void DirWidget::dirStatusChanged(QString stat){
+ if(!canmodify){ stat.prepend(tr("(Limited Access) ")); }
+ ui->label_status->setText(stat);
+}
+
+void DirWidget::setCurrentBrowser(QString id){
+ //qDebug() << "Set Current Browser:" << id;
+ if(id==cBID){ return; } //no change
+ cBID = id;
+ currentDirectoryChanged(true); //update all the averarching widget elements (widget only)
+ //Now adjust the frame/highlighting around the "active" browser
+ if(RCBW==0){ BW->setShowActive(true); }
+ else{
+ BW->setShowActive( cBID.isEmpty() );
+ RCBW->setShowActive( !cBID.isEmpty() );
+ }
+}
+
+//Context Menu Functions
+void DirWidget::createNewFile(){
+ if(!canmodify){ return; } //cannot create anything here
+ //Prompt for the new filename
+ bool ok = false;
+ QString newdocument = QInputDialog::getText(this, tr("New Document"), tr("Name:"), QLineEdit::Normal, "", \
+ &ok, 0, Qt::ImhFormattedNumbersOnly | Qt::ImhUppercaseOnly | Qt::ImhLowercaseOnly);
+ if(!ok || newdocument.isEmpty()){ return; }
+ //Create the empty file
+ QString full = currentBrowser()->currentDirectory();
+ if(!full.endsWith("/")){ full.append("/"); }
+ //verify the new file does not already exist
+ if(QFile::exists(full+newdocument)){
+ QMessageBox::warning(this, tr("Invalid Name"), tr("A file or directory with that name already exists! Please pick a different name."));
+ QTimer::singleShot(0,this, SLOT(createNewFile()) ); //repeat this function
+ return;
+ }
+ QFile file(full+newdocument);
+ if(file.open(QIODevice::ReadWrite)){
+ //If successfully opened, it has created a blank file
+ file.close();
+ }else{
+ QMessageBox::warning(this, tr("Error Creating Document"), tr("The document could not be created. Please ensure that you have the proper permissions."));
+ }
+}
+
+void DirWidget::createNewDir(){
+ if(!canmodify){ return; } //cannot create anything here
+ //Prompt for the new dir name
+ bool ok = false;
+ QString newdir = QInputDialog::getText(this, tr("New Directory"), tr("Name:"), QLineEdit::Normal, "", \
+ &ok, 0, Qt::ImhFormattedNumbersOnly | Qt::ImhUppercaseOnly | Qt::ImhLowercaseOnly);
+ if(!ok || newdir.isEmpty()){ return; }
+ //Now create the new dir
+ QString full = currentBrowser()->currentDirectory();
+ if(!full.endsWith("/")){ full.append("/"); }
+ QDir dir(full); //open the current dir
+ full.append(newdir); //append the new name to the current dir
+ //Verify that the new dir does not already exist
+ if(dir.exists(full)){
+ QMessageBox::warning(this, tr("Invalid Name"), tr("A file or directory with that name already exists! Please pick a different name."));
+ QTimer::singleShot(0,this, SLOT(createNewDir()) ); //repeat this function
+ }else{
+ if(!dir.mkdir(newdir) ){
+ QMessageBox::warning(this, tr("Error Creating Directory"), tr("The directory could not be created. Please ensure that you have the proper permissions to modify the current directory."));
+ }
+ }
+}
+
+void DirWidget::createNewXDGEntry(){
+ if(!canmodify){ return; } //cannot create anything here
+ //Prompt for the new filename
+ bool ok = false;
+ QString newdocument = QInputDialog::getText(this, tr("New Document"), tr("Name:"), QLineEdit::Normal, "", \
+ &ok, 0, Qt::ImhFormattedNumbersOnly | Qt::ImhUppercaseOnly | Qt::ImhLowercaseOnly);
+ if(!ok || newdocument.isEmpty()){ return; }
+ if(!newdocument.endsWith(".desktop")){ newdocument.append(".desktop"); }
+ //Create the empty file
+ QString full = currentBrowser()->currentDirectory();
+ if(!full.endsWith("/")){ full.append("/"); }
+ //Verify the file does not already exist
+ if(QFile::exists(full+newdocument)){
+ QMessageBox::warning(this, tr("Invalid Name"), tr("A file or directory with that name already exists! Please pick a different name."));
+ QTimer::singleShot(0,this, SLOT(createNewFile()) ); //repeat this function
+ return;
+ }
+ QProcess::startDetached("lumina-fileinfo -application \""+full+newdocument+"\"");
+}
+
+/*void DirWidget::createNewSymlink{
+
+ }*/
+
+// - Selected FILE operations
+
+//---------------------------------------------------//
+/*
+QStringList DirWidget::getPreferredApplications(){
+ QStringList out;
+ //First list all the applications registered for that same mimetype
+ QString mime = fileEXT;
+ out << LXDG::findAvailableAppsForMime(mime);
+
+ //Now search the internal settings for that extension and find any applications last used
+ QStringList keys = settings->allKeys();
+ for(int i=0; i<keys.length(); i++){
+ if(keys[i].startsWith("default/")){ continue; } //ignore the defaults (they will also be in the main)
+ if(keys[i].toLower() == fileEXT.toLower()){
+ QStringList files = settings->value(keys[i]).toString().split(":::");
+ qDebug() << "Found Files:" << keys[i] << files;
+ bool cleaned = false;
+ for(int j=0; j<files.length(); j++){
+ if(QFile::exists(files[j])){ out << files[j]; }
+ else{ files.removeAt(j); j--; cleaned=true; } //file no longer available - remove it
+ }
+ if(cleaned){ settings->setValue(keys[i], files.join(":::")); } //update the registry
+ if(!out.isEmpty()){ break; } //already found files
+ }
+ }
+ //Make sure we don't have any duplicates before we return the list
+ out.removeDuplicates();
+ return out;
+}
+ */
+ //---------------------------------------------------//
+
+void DirWidget::cutFiles(){
+ QStringList sel = currentBrowser()->currentSelection();
+ if(sel.isEmpty() || !canmodify){ return; }
+ emit CutFiles(sel);
+}
+
+void DirWidget::copyFiles(){
+ QStringList sel = currentBrowser()->currentSelection();
+ if(sel.isEmpty()){ return; }
+ emit CopyFiles(sel);
+}
+
+void DirWidget::pasteFiles(){
+ if( !canmodify ){ return; }
+ emit PasteFiles(currentBrowser()->currentDirectory(), QStringList() );
+}
+
+void DirWidget::renameFiles(){
+ QStringList sel = currentBrowser()->currentSelection();
+ if(sel.isEmpty() || !canmodify){ return; }
+ qDebug() << "Deleting selected Items:" << sel;
+ emit RenameFiles(sel);
+}
+
+void DirWidget::favoriteFiles(){
+ QStringList sel = currentBrowser()->currentSelection();
+ if(sel.isEmpty()){ return; }
+ emit FavoriteFiles(sel);
+}
+
+void DirWidget::removeFiles(){
+ QStringList sel = currentBrowser()->currentSelection();
+ if(sel.isEmpty() || !canmodify){ return; }
+ qDebug() << "Deleting selected Items:" << sel;
+ emit RemoveFiles(sel);
+}
+
+void DirWidget::runFiles(){
+ QStringList sel = currentBrowser()->currentSelection();
+ if(sel.isEmpty()){ return; }
+ QStringList dirs;
+ for(int i=0; i<sel.length(); i++){
+ if(QFileInfo(sel[i]).isDir()){
+ dirs << sel[i];
+ }else{
+ QProcess::startDetached("lumina-open \""+sel[i]+"\"");
+ }
+ }
+ if(!dirs.isEmpty()){
+ currentBrowser()->changeDirectory( dirs.takeFirst()); //load the first directory in this widget
+ }
+ if(!dirs.isEmpty()){
+ emit OpenDirectories(dirs); //open the rest of the directories in other tabs
+ }
+}
+
+void DirWidget::runWithFiles(){
+ QStringList sel = currentBrowser()->currentSelection();
+ if(sel.isEmpty()){ return; }
+ QStringList dirs;
+ for(int i=0; i<sel.length(); i++){
+ if(QFileInfo(sel[i]).isDir()){
+ dirs << sel[i];
+ }else{
+ QProcess::startDetached("lumina-open -select \""+sel[i]+"\"");
+ }
+ }
+ if(!dirs.isEmpty()){
+ emit OpenDirectories(dirs); //open the rest of the directories in other tabs
+ }
+}
+
+/*void DirWidget::attachToNewEmail(){
+
+}*/
+
+// - Context-specific operations
+void DirWidget::openInSlideshow(){
+ QStringList sel = currentBrowser()->currentSelection();
+ if(sel.isEmpty()){ sel = currentDirFiles(); }
+ //Now turn them all into a list and emit them
+ LFileInfoList list;
+ for(int i=0; i<sel.length(); i++){
+ if(sel.endsWith(".desktop")){ continue; } //simplification to make sure we don't read any files which are not needed
+ LFileInfo info(sel[i]);
+ if( info.isImage() ){ list << info; } //add to the list
+ }
+ if(!list.isEmpty()){ emit ViewFiles(list); }
+}
+
+void DirWidget::openMultimedia(){
+ QStringList sel = currentBrowser()->currentSelection();
+ if(sel.isEmpty()){ sel = currentDirFiles(); }
+ //Now turn them all into a list and emit them
+ LFileInfoList list;
+ for(int i=0; i<sel.length(); i++){
+ if(sel.endsWith(".desktop")){ continue; } //simplification to make sure we don't read any files which are not needed
+ LFileInfo info(sel[i]);
+ if( info.isAVFile() ){ list << info; } //add to the list
+ }
+ if(!list.isEmpty()){ emit PlayFiles(list); }
+}
+
+void DirWidget::OpenWithApp(QAction* act){
+ if(act->whatsThis().isEmpty()){ return; }
+ QStringList sel = currentBrowser()->currentSelection();
+ //Now we need to open the app file, and create the process
+ XDGDesktop desk(act->whatsThis());
+ QString exec = desk.generateExec(sel);
+ ExternalProcess::launch(exec);
+}
+
+void DirWidget::autoExtractFiles(){
+ QStringList files = currentBrowser()->currentSelection();
+ qDebug() << "Starting auto-extract:" << files;
+ ExternalProcess::launch("lumina-archiver", QStringList() << "--ax" << files);
+ /*ExternalProcess *pExtract= new ExternalProcess(this);
+ QString program = "lumina-archiver --ax ";
+ QStringList files = currentBrowser()->currentSelection();
+ for(int i=0; i<files.length(); i++){
+ QString runline = program + files[i];
+ pExtract->start(runline);*/
+}
+
+//====================
+// 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-dev/widgets/DirWidget2.h b/src-qt5/desktop-utils/lumina-fm-dev/widgets/DirWidget2.h
new file mode 100644
index 00000000..e1dafaa8
--- /dev/null
+++ b/src-qt5/desktop-utils/lumina-fm-dev/widgets/DirWidget2.h
@@ -0,0 +1,193 @@
+//===========================================
+// 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 <QFileSystemModel>
+#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();
+ QFileSystemModel *dirtreeModel;
+ QStringList PREFAPPS;
+
+ //View Settings
+ void setShowDetails(bool show);
+ void showHidden(bool show);
+ void showThumbnails(bool show);
+ void setThumbnailSize(int px);
+ void setFocusLineDir();
+ void adjustTreeWidget(float percent); //percent between 0-100
+
+
+
+public slots:
+ //void LoadDir(QString dir, LFileInfoList list);
+ void LoadSnaps(QString basedir, QStringList snaps);
+
+ //Refresh options
+ void refresh(); //Refresh current directory
+
+ //Theme change functions
+ void UpdateIcons();
+ void UpdateText();
+
+
+private:
+ Ui::DirWidget *ui;
+ BrowserWidget *BW, *RCBW; //Main BrowserWidget and right-column browser widget
+ QString ID, cBID; //unique ID assigned by the parent, and currently active browser widget
+ QString normalbasedir, snapbasedir, snaprelpath; //for maintaining directory context while moving between snapshots
+ QStringList snapshots, needThumbs, tmpSel;
+ bool canmodify;
+
+ //The Toolbar and associated items
+ QToolBar *toolbar;
+ QLineEdit *line_dir;
+
+ //The context menu and associated items
+ QMenu *contextMenu, *cNewMenu, *cOpenMenu, *cFModMenu, *cFViewMenu, *cOpenWithMenu;
+
+ //The keyboard shortcuts for context menu items
+ QShortcut *kZoomIn, *kZoomOut, *kNewFile, *kNewDir, *kNewXDG, *kCut, *kCopy, *kPaste, *kRename, \
+ *kFav, *kDel, *kOpSS, *kOpMM, *kOpTerm, *kExtract;
+
+ //Functions for internal use
+ void createShortcuts(); //on init only
+ void createMenus(); //on init only
+
+ BrowserWidget* currentBrowser();
+ QStringList currentDirFiles(); //all the "files" available within the current dir/browser
+
+ //QProcess *pExtract;
+
+ //OpenWithMenu
+ QString fileEXT, filePath;
+ QStringList mimetypes, keys, files;
+ //QStringList getPreferredApplications();
+
+
+private slots:
+ //UI BUTTONS/Actions
+ void splitterMoved();
+
+ // -- 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);
+ void on_folderViewPane_clicked(const QModelIndex &index);
+
+ //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();
+ void autoExtractFiles();
+
+ // - Context-specific operations
+ void openInSlideshow();
+ void openMultimedia();
+ void OpenWithApp(QAction*);
+
+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)
+ void treeWidgetSizeChanged(float); //percent width
+
+ //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-dev/widgets/DirWidget2.ui b/src-qt5/desktop-utils/lumina-fm-dev/widgets/DirWidget2.ui
new file mode 100644
index 00000000..277d8bfb
--- /dev/null
+++ b/src-qt5/desktop-utils/lumina-fm-dev/widgets/DirWidget2.ui
@@ -0,0 +1,261 @@
+<?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="QVBoxLayout" name="verticalLayout" stretch="0,0,1,0">
+ <item>
+ <layout class="QHBoxLayout" name="toolbar_layout"/>
+ </item>
+ <item>
+ <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>
+ </layout>
+ </item>
+ <item>
+ <widget class="QWidget" name="widget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QSplitter" name="splitter">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <widget class="QTreeView" name="folderViewPane">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="indentation">
+ <number>15</number>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QWidget" name="horizontalLayoutWidget">
+ <layout class="QHBoxLayout" name="browser_layout"/>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <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>Single Column</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>
diff --git a/src-qt5/desktop-utils/lumina-fm-dev/widgets/MultimediaWidget.cpp b/src-qt5/desktop-utils/lumina-fm-dev/widgets/MultimediaWidget.cpp
new file mode 100644
index 00000000..eaa15a59
--- /dev/null
+++ b/src-qt5/desktop-utils/lumina-fm-dev/widgets/MultimediaWidget.cpp
@@ -0,0 +1,222 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "MultimediaWidget.h"
+#include "ui_MultimediaWidget.h"
+
+#include <QTimer>
+
+MultimediaWidget::MultimediaWidget(QWidget *parent) : QWidget(parent), ui(new Ui::MultimediaWidget){
+ ui->setupUi(this); //load the designer file
+
+ //Add in the special QMultimediaWidgets
+ mediaObj = new QMediaPlayer(this);
+ mediaObj->setVolume(100);
+ mediaObj->setNotifyInterval(500); //only every 1/2 second update
+ videoDisplay = new QVideoWidget(this);
+ videoDisplay->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ ui->videoLayout->addWidget(videoDisplay);
+ mediaObj->setVideoOutput(videoDisplay);
+ videoDisplay->setVisible(false);
+
+ UpdateIcons();
+ UpdateText();
+
+ //Connect the special signals/slots for the media object
+ connect(mediaObj, SIGNAL(durationChanged(qint64)), this, SLOT(playerDurationChanged(qint64)) );
+ connect(mediaObj, SIGNAL(seekableChanged(bool)), ui->playerSlider, SLOT(setEnabled(bool)) );
+ connect(mediaObj, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), this, SLOT(playerStatusChanged(QMediaPlayer::MediaStatus)) );
+ connect(mediaObj, SIGNAL(positionChanged(qint64)), this, SLOT(playerTimeChanged(qint64)) );
+ connect(mediaObj, SIGNAL(stateChanged(QMediaPlayer::State)), this, SLOT(playerStateChanged(QMediaPlayer::State)) );
+ connect(mediaObj, SIGNAL(videoAvailableChanged(bool)), this, SLOT(playerVideoAvailable(bool)) );
+ connect(mediaObj, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(playerError()) );
+
+ //Disable some of the initial states
+ ui->tool_player_stop->setEnabled(false); //nothing to stop yet
+ ui->tool_player_pause->setVisible(false); //nothing to pause yet
+ ui->playerSlider->setEnabled(false); //nothing to seek yet
+}
+
+MultimediaWidget::~MultimediaWidget(){
+
+}
+
+// ================
+// PUBLIC SLOTS
+// ================
+void MultimediaWidget::ClearPlaylist(){
+ mediaObj->stop();
+ ui->combo_player_list->clear();
+}
+
+void MultimediaWidget::LoadMultimedia(QList<LFileInfo> list){
+ for(int i=0; i<list.length(); i++){
+ if(list[i].isAVFile()){ ui->combo_player_list->addItem(list[i].fileName(), list[i].absoluteFilePath() ); }
+ }
+}
+
+void MultimediaWidget::Cleanup(){
+ mediaObj->stop(); //just make sure the player is stopped
+}
+
+//Theme change functions
+void MultimediaWidget::UpdateIcons(){
+ ui->tool_player_next->setIcon( LXDG::findIcon("media-skip-forward","") );
+ ui->tool_player_prev->setIcon( LXDG::findIcon("media-skip-backward","") );
+ ui->tool_player_pause->setIcon( LXDG::findIcon("media-playback-pause","") );
+ ui->tool_player_play->setIcon( LXDG::findIcon("media-playback-start","") );
+ ui->tool_player_stop->setIcon( LXDG::findIcon("media-playback-stop","") );
+}
+
+void MultimediaWidget::UpdateText(){
+ ui->retranslateUi(this);
+}
+
+
+// =================
+// PRIVATE
+// =================
+QString MultimediaWidget::msToText(qint64 ms){
+ QString disp;
+ if(ms>3600000){
+ disp.append( QString::number(ms/3600000)+":" );
+ ms = ms%3600000;
+ }
+ if(ms>60000){
+ disp.append( QString::number(ms/60000)+":" );
+ ms = ms%60000;
+ }else{
+ disp.append("0:");
+ }
+ if(ms>1000){
+ if(ms>=10000){ disp.append( QString::number(ms/1000) ); }
+ else{ disp.append( "0"+QString::number(ms/1000) ); }
+ }else{
+ disp.append("00");
+ }
+ return disp;
+}
+
+// =================
+// PRIVATE SLOTS
+// =================
+void MultimediaWidget::playerStatusChanged(QMediaPlayer::MediaStatus stat){
+ //Only use this for end-of-file detection - use the state detection otherwise
+ if(stat == QMediaPlayer::EndOfMedia){
+ if(!mediaObj->isMuted()){ playerFinished(); } //make sure it is not being seeked right now
+ }
+}
+
+void MultimediaWidget::playerStateChanged(QMediaPlayer::State newstate){
+ //This function keeps track of updating the visuals of the player
+ bool running = false;
+ bool showVideo = false;
+ QString msg;
+ switch(newstate){
+ case QMediaPlayer::PlayingState:
+ running=true;
+ showVideo = mediaObj->isVideoAvailable();
+ msg = "";//mediaObj->metaData(Phonon::TitleMetaData).join(" ");
+ if(msg.simplified().isEmpty()){ msg = ui->combo_player_list->currentText(); }
+ ui->label_player_novideo->setText(tr("Playing:")+"\n"+msg);
+ break;
+ case QMediaPlayer::PausedState:
+ showVideo=videoDisplay->isVisible(); //don't change the screen
+ break;
+ case QMediaPlayer::StoppedState:
+ ui->label_player_novideo->setText(tr("Stopped"));
+ break;
+ }
+ ui->tool_player_play->setVisible(!running);
+ ui->tool_player_pause->setVisible(running);
+ ui->tool_player_stop->setEnabled(running);
+ ui->label_player_novideo->setVisible(!showVideo);
+ videoDisplay->setVisible(showVideo);
+}
+
+void MultimediaWidget::playerVideoAvailable(bool showVideo){
+ ui->label_player_novideo->setVisible(!showVideo);
+ videoDisplay->setVisible(showVideo);
+}
+
+void MultimediaWidget::playerDurationChanged(qint64 dur){
+ if(dur < 0){ return; } //not ready yet
+ ui->playerSlider->setMaximum(mediaObj->duration());
+ playerTTime = msToText(dur);
+}
+
+void MultimediaWidget::playerTimeChanged(qint64 ctime){
+ if(mediaObj->isMuted() || playerTTime.isEmpty() ){ return; } //currently being moved
+ ui->playerSlider->setSliderPosition(ctime);
+}
+
+void MultimediaWidget::playerError(){
+ QString msg = QString(tr("Error Playing File: %1"));
+ msg = msg.arg( mediaObj->currentMedia().canonicalUrl().fileName() );
+ msg.append("\n"+mediaObj->errorString());
+ ui->label_player_novideo->setText(msg);
+}
+
+void MultimediaWidget::playerFinished(){
+ if(ui->combo_player_list->currentIndex()<(ui->combo_player_list->count()-1) && ui->check_player_gotonext->isChecked()){
+ ui->combo_player_list->setCurrentIndex( ui->combo_player_list->currentIndex()+1 );
+ QTimer::singleShot(0,this,SLOT(on_tool_player_play_clicked()));
+ }else{
+ ui->label_player_novideo->setText(tr("Finished"));
+ }
+}
+
+void MultimediaWidget::on_tool_player_play_clicked(){
+ if(mediaObj->state()==QMediaPlayer::PausedState \
+ && mediaObj->currentMedia().canonicalUrl().fileName()==ui->combo_player_list->currentText() ){
+ mediaObj->play();
+ }else{
+ mediaObj->stop();
+ //Get the selected file path
+ QString filePath = ui->combo_player_list->currentData().toString();
+ mediaObj->setMedia( QUrl::fromLocalFile(filePath) );
+ playerTTime.clear();
+ ui->playerSlider->setEnabled(mediaObj->isSeekable());
+ mediaObj->play();
+ }
+}
+
+void MultimediaWidget::on_combo_player_list_currentIndexChanged(int index){
+ ui->tool_player_next->setEnabled( ui->combo_player_list->count() > (index+1) );
+ ui->tool_player_prev->setEnabled( (index-1) >= 0 );
+}
+
+void MultimediaWidget::on_tool_player_next_clicked(){
+ ui->combo_player_list->setCurrentIndex( ui->combo_player_list->currentIndex()+1);
+ if(mediaObj->state()!=QMediaPlayer::StoppedState){ on_tool_player_play_clicked(); }
+}
+
+void MultimediaWidget::on_tool_player_prev_clicked(){
+ ui->combo_player_list->setCurrentIndex( ui->combo_player_list->currentIndex()-1);
+ if(mediaObj->state()!=QMediaPlayer::StoppedState){ on_tool_player_play_clicked(); }
+}
+
+void MultimediaWidget::on_tool_player_pause_clicked(){
+ mediaObj->pause();
+}
+
+void MultimediaWidget::on_tool_player_stop_clicked(){
+ mediaObj->stop();
+}
+
+//Slider controls
+void MultimediaWidget::on_playerSlider_sliderPressed(){
+ mediaObj->setMuted(true);
+ mediaObj->pause();
+}
+void MultimediaWidget::on_playerSlider_sliderReleased(){
+ if(mediaObj->state()==QMediaPlayer::PausedState){ mediaObj->play(); }
+ mediaObj->setMuted(false);
+}
+void MultimediaWidget::on_playerSlider_valueChanged(int val){
+ ui->label_player_runstats->setText( msToText(val)+"/"+playerTTime );
+ if(mediaObj->isMuted()){ mediaObj->setPosition(val); } //currently seeking
+}
diff --git a/src-qt5/desktop-utils/lumina-fm-dev/widgets/MultimediaWidget.h b/src-qt5/desktop-utils/lumina-fm-dev/widgets/MultimediaWidget.h
new file mode 100644
index 00000000..c579b2dd
--- /dev/null
+++ b/src-qt5/desktop-utils/lumina-fm-dev/widgets/MultimediaWidget.h
@@ -0,0 +1,71 @@
+//===========================================
+// 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_MULTIMEDIA_WIDGET_H
+#define _LUMINA_FM_MULTIMEDIA_WIDGET_H
+
+#include <QList>
+#include <QWidget>
+#include <QObject>
+#include <QMediaObject>
+#include <QMediaPlayer>
+#include <QVideoWidget>
+
+#include "../DirData.h"
+
+namespace Ui{
+ class MultimediaWidget;
+};
+
+class MultimediaWidget : public QWidget{
+ Q_OBJECT
+public:
+ MultimediaWidget(QWidget *parent = 0);
+ ~MultimediaWidget();
+
+public slots:
+ void ClearPlaylist();
+ void LoadMultimedia(QList<LFileInfo> list);
+ void Cleanup(); //perform actions necessary when closing the player
+
+ //Theme change functions
+ void UpdateIcons();
+ void UpdateText();
+
+private:
+ Ui::MultimediaWidget *ui;
+ QMediaPlayer *mediaObj;
+ QVideoWidget *videoDisplay;
+ QString playerTTime; //total time - to prevent recalculation every tick
+
+ QString msToText(qint64 ms);
+
+private slots:
+ //Media Object functions
+ void playerStatusChanged(QMediaPlayer::MediaStatus stat);
+ void playerStateChanged(QMediaPlayer::State newstate);
+ void playerVideoAvailable(bool showVideo);
+ void playerDurationChanged(qint64 dur);
+ void playerTimeChanged(qint64 ctime);
+ void playerError();
+ void playerFinished();
+
+ //The UI functions
+ void on_tool_player_play_clicked();
+ void on_combo_player_list_currentIndexChanged(int index);
+ void on_tool_player_next_clicked();
+ void on_tool_player_prev_clicked();
+ void on_tool_player_pause_clicked();
+ void on_tool_player_stop_clicked();
+
+ //Slider controls
+ void on_playerSlider_sliderPressed();
+ void on_playerSlider_sliderReleased();
+ void on_playerSlider_valueChanged(int val);
+
+
+};
+#endif \ No newline at end of file
diff --git a/src-qt5/desktop-utils/lumina-fm-dev/widgets/MultimediaWidget.ui b/src-qt5/desktop-utils/lumina-fm-dev/widgets/MultimediaWidget.ui
new file mode 100644
index 00000000..67805e13
--- /dev/null
+++ b/src-qt5/desktop-utils/lumina-fm-dev/widgets/MultimediaWidget.ui
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MultimediaWidget</class>
+ <widget class="QWidget" name="MultimediaWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QCheckBox" name="check_player_gotonext">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Go To Next</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line_3">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>30</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_player_prev">
+ <property name="text">
+ <string notr="true">prev</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="combo_player_list">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_player_next">
+ <property name="text">
+ <string notr="true">next</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="videoLayout">
+ <item>
+ <widget class="QLabel" name="label_player_novideo">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>13</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background: black; color: white;</string>
+ </property>
+ <property name="text">
+ <string>(No Running Video)</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="videoControlLayout">
+ <item>
+ <widget class="QToolButton" name="tool_player_play">
+ <property name="text">
+ <string notr="true">play</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_player_pause">
+ <property name="text">
+ <string notr="true">pause</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_player_stop">
+ <property name="text">
+ <string notr="true">stop</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line_4">
+ <property name="minimumSize">
+ <size>
+ <width>30</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSlider" name="playerSlider">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_player_runstats">
+ <property name="text">
+ <string notr="true">?/?</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src-qt5/desktop-utils/lumina-fm-dev/widgets/SlideshowWidget.cpp b/src-qt5/desktop-utils/lumina-fm-dev/widgets/SlideshowWidget.cpp
new file mode 100644
index 00000000..a9028d2b
--- /dev/null
+++ b/src-qt5/desktop-utils/lumina-fm-dev/widgets/SlideshowWidget.cpp
@@ -0,0 +1,169 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "SlideshowWidget.h"
+#include "ui_SlideshowWidget.h"
+
+#include <QImageWriter>
+#include <QMessageBox>
+
+SlideshowWidget::SlideshowWidget(QWidget *parent) : QWidget(parent), ui(new Ui::SlideshowWidget){
+ ui->setupUi(this); //load the designer file
+ zoom = 1;
+ UpdateIcons();
+ UpdateText();
+}
+
+SlideshowWidget::~SlideshowWidget(){
+
+}
+
+// ================
+// PUBLIC SLOTS
+// ================
+void SlideshowWidget::ClearImages(){
+ ui->combo_image_name->clear();
+}
+
+void SlideshowWidget::LoadImages(QList<LFileInfo> list){
+ int cmax = ui->combo_image_name->count(); //current number of items
+ for(int i=0; i<list.length(); i++){
+ if(list[i].isImage()){ ui->combo_image_name->addItem(list[i].fileName(), list[i].absoluteFilePath() ); }
+ }
+ //Now automatically show the first item from the batch of new ones
+ if(cmax < ui->combo_image_name->count()){ ui->combo_image_name->setCurrentIndex(cmax); }
+}
+
+void SlideshowWidget::refresh(){
+ UpdateImage();
+}
+
+//Theme change functions
+void SlideshowWidget::UpdateIcons(){
+ ui->tool_image_goBegin->setIcon( LXDG::findIcon("go-first-view","") );
+ ui->tool_image_goEnd->setIcon( LXDG::findIcon("go-last-view","") );
+ ui->tool_image_goPrev->setIcon( LXDG::findIcon("go-previous-view","") );
+ ui->tool_image_goNext->setIcon( LXDG::findIcon("go-next-view","") );
+ ui->tool_image_remove->setIcon( LXDG::findIcon("edit-delete","") );
+ ui->tool_image_rotateleft->setIcon( LXDG::findIcon("object-rotate-left","") );
+ ui->tool_image_rotateright->setIcon( LXDG::findIcon("object-rotate-right","") );
+ ui->tool_image_zoomin->setIcon( LXDG::findIcon("zoom-in","") );
+ ui->tool_image_zoomout->setIcon( LXDG::findIcon("zoom-out","") );
+}
+
+void SlideshowWidget::UpdateText(){
+ ui->retranslateUi(this);
+}
+
+
+// =================
+// PRIVATE
+// =================
+void SlideshowWidget::UpdateImage(){
+ QString file = ui->combo_image_name->currentData().toString();
+ qDebug() << "Show Image:" << file << "Zoom:" << zoom;
+ QPixmap pix(file);
+ QSize sz = ui->scrollArea->contentsRect().size();
+ if( sz.width()>pix.size().width() || sz.height()>pix.size().height()){ sz = pix.size(); } //100% size already - apply zoom after this
+ pix = pix.scaled(sz*zoom, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ ui->label_image->setPixmap(pix);
+ //Now set/load the buttons
+ ui->tool_image_goBegin->setEnabled(ui->combo_image_name->currentIndex()>0);
+ ui->tool_image_goPrev->setEnabled(ui->combo_image_name->currentIndex()>0);
+ ui->tool_image_goEnd->setEnabled(ui->combo_image_name->currentIndex()<(ui->combo_image_name->count()-1));
+ ui->tool_image_goNext->setEnabled(ui->combo_image_name->currentIndex()<(ui->combo_image_name->count()-1));
+ ui->label_image_index->setText( QString::number(ui->combo_image_name->currentIndex()+1)+"/"+QString::number(ui->combo_image_name->count()) );
+ static QList<QByteArray> writeableformats;
+ if(writeableformats.isEmpty()){
+ writeableformats = QImageWriter::supportedImageFormats();
+ qDebug() << "Writeable image formats:" << writeableformats;
+ }
+ bool canwrite = writeableformats.contains(file.section(".",-1).toLower().toLocal8Bit()); //compare the suffix with the list
+ bool isUserWritable = QFileInfo(file).isWritable();
+ ui->tool_image_remove->setEnabled(isUserWritable);
+ ui->tool_image_rotateleft->setEnabled(isUserWritable && canwrite);
+ ui->tool_image_rotateright->setEnabled(isUserWritable && canwrite);
+ ui->tool_image_zoomin->setEnabled(zoom<2);
+ ui->tool_image_zoomout->setEnabled(zoom>0.25);
+}
+
+
+// =================
+// PRIVATE SLOTS
+// =================
+// Picture rotation options
+void SlideshowWidget::on_combo_image_name_currentIndexChanged(int index){
+ if(index>=0 && !ui->combo_image_name->currentData().toString().isEmpty()){
+ zoom = 1; //always reset the zoom level when changing images
+ UpdateImage();
+ }
+}
+
+void SlideshowWidget::on_tool_image_goEnd_clicked(){
+ ui->combo_image_name->setCurrentIndex( ui->combo_image_name->count()-1 );
+}
+
+void SlideshowWidget::on_tool_image_goNext_clicked(){
+ ui->combo_image_name->setCurrentIndex( ui->combo_image_name->currentIndex()+1 );
+}
+
+void SlideshowWidget::on_tool_image_goPrev_clicked(){
+ ui->combo_image_name->setCurrentIndex( ui->combo_image_name->currentIndex()-1 );
+}
+
+void SlideshowWidget::on_tool_image_goBegin_clicked(){
+ ui->combo_image_name->setCurrentIndex(0);
+}
+
+// Picture modification options
+void SlideshowWidget::on_tool_image_remove_clicked(){
+ QString file = ui->combo_image_name->currentData().toString();
+ //Verify permanent removal of file/dir
+ if(QMessageBox::Yes != QMessageBox::question(this, tr("Verify Removal"), tr("WARNING: This will permanently delete the file from the system!")+"\n"+tr("Are you sure you want to continue?")+"\n\n"+file, QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ){
+ return; //cancelled
+ }
+ if( QFile::remove(file) ){
+ int index = ui->combo_image_name->currentIndex();
+ ui->combo_image_name->removeItem( index );
+ }
+}
+
+void SlideshowWidget::on_tool_image_rotateleft_clicked(){
+ //First load the file fresh (not the scaled version in the UI)
+ QString file = ui->combo_image_name->currentData().toString();
+ QPixmap pix(file);
+ //Now rotate the image 90 degrees counter-clockwise
+ QTransform trans;
+ pix = pix.transformed( trans.rotate(-90) , Qt::SmoothTransformation);
+ //Now save the image back to the same file
+ pix.save(file);
+ //Now re-load the image in the UI
+ UpdateImage();
+}
+
+void SlideshowWidget::on_tool_image_rotateright_clicked(){
+ //First load the file fresh (not the scaled version in the UI)
+ QString file = ui->combo_image_name->currentData().toString();
+ QPixmap pix(file);
+ //Now rotate the image 90 degrees counter-clockwise
+ QTransform trans;
+ pix = pix.transformed( trans.rotate(90) , Qt::SmoothTransformation);
+ //Now save the image back to the same file
+ pix.save(file);
+ //Now re-load the image in the UI
+ UpdateImage();
+}
+
+void SlideshowWidget::on_tool_image_zoomin_clicked(){
+ zoom+=0.25; //change 25% every time
+ UpdateImage();
+}
+
+void SlideshowWidget::on_tool_image_zoomout_clicked(){
+ zoom-=0.25; //change 25% every time
+ UpdateImage();
+}
+
diff --git a/src-qt5/desktop-utils/lumina-fm-dev/widgets/SlideshowWidget.h b/src-qt5/desktop-utils/lumina-fm-dev/widgets/SlideshowWidget.h
new file mode 100644
index 00000000..3b9c70fd
--- /dev/null
+++ b/src-qt5/desktop-utils/lumina-fm-dev/widgets/SlideshowWidget.h
@@ -0,0 +1,57 @@
+//===========================================
+// 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_SLIDESHOW_WIDGET_H
+#define _LUMINA_FM_SLIDESHOW_WIDGET_H
+
+#include <QList>
+#include <QWidget>
+#include <QObject>
+
+#include "../DirData.h"
+
+namespace Ui{
+ class SlideshowWidget;
+};
+
+class SlideshowWidget : public QWidget{
+ Q_OBJECT
+public:
+ SlideshowWidget(QWidget *parent = 0);
+ ~SlideshowWidget();
+
+public slots:
+ void ClearImages();
+ void LoadImages(QList<LFileInfo> list);
+
+ void refresh(); //Note: This should be called right after the widget becomes visible
+
+ //Theme change functions
+ void UpdateIcons();
+ void UpdateText();
+
+private:
+ Ui::SlideshowWidget *ui;
+ void UpdateImage();
+ double zoom;
+
+private slots:
+ // Picture rotation options
+ void on_combo_image_name_currentIndexChanged(int index);
+ void on_tool_image_goEnd_clicked();
+ void on_tool_image_goNext_clicked();
+ void on_tool_image_goPrev_clicked();
+ void on_tool_image_goBegin_clicked();
+
+ // Picture modification options
+ void on_tool_image_remove_clicked();
+ void on_tool_image_rotateleft_clicked();
+ void on_tool_image_rotateright_clicked();
+ void on_tool_image_zoomin_clicked();
+ void on_tool_image_zoomout_clicked();
+
+};
+#endif \ No newline at end of file
diff --git a/src-qt5/desktop-utils/lumina-fm-dev/widgets/SlideshowWidget.ui b/src-qt5/desktop-utils/lumina-fm-dev/widgets/SlideshowWidget.ui
new file mode 100644
index 00000000..cab4c5f9
--- /dev/null
+++ b/src-qt5/desktop-utils/lumina-fm-dev/widgets/SlideshowWidget.ui
@@ -0,0 +1,346 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SlideshowWidget</class>
+ <widget class="QWidget" name="SlideshowWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <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>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <widget class="QToolButton" name="tool_image_remove">
+ <property name="toolTip">
+ <string>Delete this image file</string>
+ </property>
+ <property name="text">
+ <string notr="true">...</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line_8">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_image_rotateleft">
+ <property name="toolTip">
+ <string>Rotate this image file counter-clockwise</string>
+ </property>
+ <property name="text">
+ <string notr="true">...</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_image_rotateright">
+ <property name="toolTip">
+ <string>Rotate this image file clockwise</string>
+ </property>
+ <property name="text">
+ <string notr="true">...</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_image_zoomin">
+ <property name="toolTip">
+ <string>Zoom in</string>
+ </property>
+ <property name="statusTip">
+ <string>Zoom in</string>
+ </property>
+ <property name="text">
+ <string notr="true">...</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_image_zoomout">
+ <property name="toolTip">
+ <string>Zoom out</string>
+ </property>
+ <property name="statusTip">
+ <string>Zoom out</string>
+ </property>
+ <property name="text">
+ <string notr="true">...</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QScrollArea" name="scrollArea">
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>364</width>
+ <height>264</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_image">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_image_goBegin">
+ <property name="focusPolicy">
+ <enum>Qt::NoFocus</enum>
+ </property>
+ <property name="toolTip">
+ <string>Go to Beginning</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="shortcut">
+ <string>Shift+Left</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_image_goPrev">
+ <property name="focusPolicy">
+ <enum>Qt::NoFocus</enum>
+ </property>
+ <property name="toolTip">
+ <string>Go to Previous</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="shortcut">
+ <string>Left</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="combo_image_name">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::StrongFocus</enum>
+ </property>
+ <property name="frame">
+ <bool>true</bool>
+ </property>
+ <item>
+ <property name="text">
+ <string>File Name</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_image_index">
+ <property name="text">
+ <string notr="true">1/10</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_image_goNext">
+ <property name="focusPolicy">
+ <enum>Qt::NoFocus</enum>
+ </property>
+ <property name="toolTip">
+ <string>Go to Next</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="shortcut">
+ <string>Right</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_image_goEnd">
+ <property name="focusPolicy">
+ <enum>Qt::NoFocus</enum>
+ </property>
+ <property name="toolTip">
+ <string>Go to End</string>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="shortcut">
+ <string>Shift+Right</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
bgstack15