diff options
Diffstat (limited to 'src-qt5/desktop-utils/lumina-fm-dev/widgets')
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> |