//=========================================== // Lumina-DE source code // Copyright (c) 2015, Ken Moore // Available under the 3-clause BSD license // See the LICENSE file for full details //=========================================== #include #include "MainUI.h" #include "ui_MainUI.h" #include #include #include #include #include MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI){ ui->setupUi(this); //load the designer form canwrite = false; terminate_thread = false; INFO = new LFileInfo(); UpdateIcons(); //Set all the icons in the dialog SetupConnections(); //Disable buttons that are not working yet //ui->actionOpen_File->setVisible(false); //ui->actionOpen_Directory->setVisible(false); //ui->menuSave_As->setEnabled(false); } MainUI::~MainUI(){ terminate_thread = true; this->close(); } //============= // PUBLIC //============= void MainUI::LoadFile(QString path, QString type){ //Do the first file information tab qDebug() << "Load File:" << path << type; INFO = new LFileInfo(path); //First load the general file information if(!INFO->filePath().isEmpty()){ SyncFileInfo(); }else{ SetupNewFile(); } } void MainUI::UpdateIcons(){ } //============== // PRIVATE //============== void MainUI::ReloadAppIcon(){ //qDebug() << "Reload App Icon:"; ui->label_xdg_icon->setPixmap( LXDG::findIcon(ui->line_xdg_icon->text(),"").pixmap(64,64) ); //qDebug() << "Check Desktop File entry"; if(INFO->iconfile()!=ui->line_xdg_icon->text()){ xdgvaluechanged(); } //qDebug() << "Done with app icon"; } void MainUI::stopDirSize(){ if(sizeThread.isRunning()){ terminate_thread = true; sizeThread.waitForFinished(); QApplication::processEvents(); //throw away any last signals waiting to be processed } terminate_thread = false; } void MainUI::GetDirSize(const QString dirname) const { const quint16 update_frequency = 2000; //For reducing the number of folder_size_changed calls quint64 filesize = 0; quint64 file_number = 0; quint64 dir_number = 1; QDir folder(dirname); QFileInfoList file_list; QString dir_name; QList head; folder.setFilter(QDir::Hidden|QDir::AllEntries|QDir::NoDotAndDotDot); file_list = folder.entryInfoList(); for(int i=0; ifilePath().isEmpty()){ return; } if(INFO->exists()){ canwrite = INFO->isWritable(); } else{ //See if the containing directory can be written QFileInfo chk(INFO->absolutePath()); canwrite = (chk.isDir() && chk.isWritable()); } ui->label_file_name->setText( INFO->fileName() ); ui->label_file_mimetype->setText( INFO->mimetype() ); if(!INFO->isDir()){ ui->label_file_size->setText( LUtils::BytesToDisplaySize( INFO->size() ) ); } else { ui->label_file_size->setText(tr("---Calculating---")); sizeThread = QtConcurrent::run(this, &MainUI::GetDirSize, INFO->absoluteFilePath()); } ui->label_file_owner->setText(INFO->owner()); ui->label_file_group->setText(INFO->group()); ui->label_file_created->setText( INFO->birthTime().toString(Qt::SystemLocaleLongDate) ); ui->label_file_modified->setText( INFO->lastModified().toString(Qt::SystemLocaleLongDate) ); //Get the file permissions QString perms; if(INFO->isReadable() && INFO->isWritable()){ perms = tr("Read/Write"); } else if(INFO->isReadable()){ perms = tr("Read Only"); } else if(INFO->isWritable()){ perms = tr("Write Only"); } else{ perms = tr("No Access"); } ui->label_file_perms->setText(perms); //Now the special "type" for the file QString ftype; if(INFO->suffix().toLower()=="desktop"){ ftype = tr("XDG Shortcut"); } else if(INFO->isDir()){ ftype = tr("Directory"); } else if(INFO->isExecutable()){ ftype = tr("Binary"); } else{ ftype = INFO->suffix().toUpper(); } if(INFO->isHidden()){ ftype = QString(tr("Hidden %1")).arg(ftype); } ui->label_file_type->setText(ftype); //Now load the icon for the file if(INFO->isImage()){ QPixmap pix(INFO->absoluteFilePath()); ui->label_file_icon->setPixmap(pix.scaledToHeight(64)); ui->label_file_size->setText( ui->label_file_size->text()+" ("+QString::number(pix.width())+" x "+QString::number(pix.height())+" px)" ); }else if(INFO->isVideo()){ ui->label_file_icon->hide(); LVideoLabel *mediaLabel = new LVideoLabel(INFO->absoluteFilePath(), true, ui->tab_file); mediaLabel->setFixedSize(64,64); ui->formLayout->replaceWidget(ui->label_file_icon, mediaLabel); }else{ ui->label_file_icon->setPixmap( LXDG::findIcon( INFO->iconfile(), "unknown").pixmap(QSize(64,64)) ); } //qDebug() << "Check XDG Info:" //qDebug() << INFO->isDesktopFile() << type; syncXdgStruct(INFO->XDG()); //Make sure the right tabs are available if(ui->tabWidget->indexOf(ui->tab_file)<0){ //qDebug() << "Add File Info Tab"; ui->tabWidget->insertTab(0, ui->tab_file, tr("File Information")); } if(!INFO->isDesktopFile()){ if(ui->tabWidget->indexOf(ui->tab_deskedit)>=0){ ui->tabWidget->removeTab( ui->tabWidget->indexOf(ui->tab_deskedit) ); } }else if(ui->tabWidget->indexOf(ui->tab_deskedit)<0){ ui->tabWidget->addTab( ui->tab_deskedit, tr("XDG Shortcut") ); } ui->tabWidget->setCurrentIndex(ui->tabWidget->indexOf(ui->tab_file) ); SyncZfsInfo(); } void MainUI::SyncZfsInfo(){ bool showtab = false; if(INFO->zfsPool().isEmpty()){ //Not on a ZFS pool - hide the tab if it is available showtab = false; }else{ qDebug() << "Is a ZFS Dataset:" << INFO->isZfsDataset(); ui->label_zfs_pool->setText(INFO->zfsPool()); if(INFO->isZfsDataset()){ ui->tree_zfs_props->clear(); QJsonObject props = INFO->zfsProperties(); QStringList keys = props.keys(); for(int i=0; itree_zfs_props->addTopLevelItem( new QTreeWidgetItem(QStringList() << keys[i] << props.value(keys[i]).toObject().value("value").toString() << props.value(keys[i]).toObject().value("source").toString() ) ); ui->tree_zfs_props->resizeColumnToContents(0); ui->tree_zfs_props->resizeColumnToContents(1); } ui->tree_zfs_props->setVisible(!keys.isEmpty()); showtab = !keys.isEmpty(); }else{ ui->tree_zfs_props->setVisible(false); } QStringList snaps = INFO->zfsSnapshots(); ui->tree_zfs_snaps->clear(); for(int i=0; itree_zfs_snaps->addTopLevelItem( new QTreeWidgetItem(QStringList() << snaps[i].section("::::",0,0) << finfo.birthTime().toString(Qt::SystemLocaleShortDate) << finfo.lastModified().toString(Qt::SystemLocaleShortDate) ) ); ui->tree_zfs_snaps->resizeColumnToContents(0); } ui->tree_zfs_snaps->setVisible(!snaps.isEmpty()); showtab = showtab || !snaps.isEmpty(); } if(showtab){ //Make sure the tab is visible if(ui->tabWidget->indexOf(ui->tab_zfs)<0){ ui->tabWidget->addTab( ui->tab_zfs, tr("Advanced") ); } }else{ //hide the tab if it is visible right now if(ui->tabWidget->indexOf(ui->tab_zfs)>=0){ ui->tabWidget->removeTab( ui->tabWidget->indexOf(ui->tab_zfs) ); } } } void MainUI::SetupNewFile(){ //qDebug() << "Setup New File"; if(!INFO->filePath().isEmpty()){ INFO = new LFileInfo(); } stopDirSize(); canwrite = true; //can always write a new file syncXdgStruct(INFO->XDG()); //Make sure the right tabs are enabled if(ui->tabWidget->indexOf(ui->tab_file)>=0){ ui->tabWidget->removeTab( ui->tabWidget->indexOf(ui->tab_file) ); } if(ui->tabWidget->indexOf(ui->tab_deskedit)<0){ //qDebug() << "Adding the deskedit tab"; ui->tabWidget->addTab(ui->tab_deskedit, tr("XDG Shortcut")); } //Not on a ZFS pool - hide the tab if it is available if(ui->tabWidget->indexOf(ui->tab_zfs)>=0){ ui->tabWidget->removeTab( ui->tabWidget->indexOf(ui->tab_zfs) ); } ui->tabWidget->setCurrentIndex(ui->tabWidget->indexOf(ui->tab_deskedit) ); } void MainUI::syncXdgStruct(XDGDesktop *XDG){ bool cleanup = false; if(XDG==0){ XDG = new XDGDesktop(); cleanup = true;} //make sure nothing crashes if(XDG->type == XDGDesktop::APP){ ui->line_xdg_command->setText(XDG->exec); ui->line_xdg_wdir->setText(XDG->path); ui->check_xdg_useTerminal->setChecked( XDG->useTerminal ); ui->check_xdg_startupNotify->setChecked( XDG->startupNotify ); }else if(XDG->type==XDGDesktop::LINK){ //Hide the options that are unavailable for links //Command line (exec) ui->line_xdg_command->setVisible(false); ui->tool_xdg_getCommand->setVisible(false); ui->lblCommand->setVisible(false); //Options ui->lblOptions->setVisible(false); ui->check_xdg_useTerminal->setVisible(false); ui->check_xdg_startupNotify->setVisible(false); //Now load the variables for this type of shortcut ui->lblWorkingDir->setText(tr("URL:")); ui->line_xdg_wdir->setText( XDG->url ); ui->tool_xdg_getDir->setVisible(false); //the dir selection button } ui->line_xdg_name->setText(XDG->name); ui->line_xdg_comment->setText(XDG->comment); ui->line_xdg_icon->setText( XDG->icon ); ReloadAppIcon(); ui->actionSave_Shortcut->setVisible(true); ui->actionSave_Shortcut->setEnabled(false); if(cleanup){ delete XDG; } checkXDGValidity(); } bool MainUI::saveFile(QString path){ //qDebug() << "Request save file:" << path; XDGDesktop *XDG = INFO->XDG(); if(XDG==0){ XDG = new XDGDesktop(); } if(XDG->type == XDGDesktop::BAD){ XDG->type = XDGDesktop::APP; } //Update the file path in the data structure XDG->filePath = path; //Now change the structure XDG->name = ui->line_xdg_name->text(); XDG->genericName = ui->line_xdg_name->text().toLower(); XDG->comment = ui->line_xdg_comment->text(); XDG->icon = ui->line_xdg_icon->text(); //Now do the type-specific fields if(XDG->type == XDGDesktop::APP){ XDG->exec = ui->line_xdg_command->text(); XDG->tryexec = ui->line_xdg_command->text().section(" ",0,0); //use the first word/binary for the existance check XDG->path = ui->line_xdg_wdir->text(); //working dir/path XDG->useTerminal = ui->check_xdg_useTerminal->isChecked(); XDG->startupNotify = ui->check_xdg_startupNotify->isChecked(); }else if(XDG->type==XDGDesktop::LINK){ XDG->url = ui->line_xdg_wdir->text(); //we re-used this field } //Clear any info which this utility does not support at the moment XDG->actionList.clear(); XDG->actions.clear(); //Now save the structure to file //qDebug() << "Saving File:" << XDG->filePath; return XDG->saveDesktopFile(true); //Try to merge the file/structure as necessary } QString MainUI::findOpenDirFile(bool isdir){ static QList urls; if(urls.isEmpty()){ urls << QUrl::fromLocalFile("/"); QStringList dirs = QString(getenv("XDG_DATA_DIRS")).split(":"); for(int i=0; iactionQuit, SIGNAL(triggered()), this, SLOT(closeApplication()) ); connect(ui->actionSave_Shortcut, SIGNAL(triggered()), this, SLOT(save_clicked()) ); connect(ui->actionLocal_Shortcut, SIGNAL(triggered()), this, SLOT(save_as_local_clicked()) ); connect(ui->actionRegister_Shortcut, SIGNAL(triggered()), this, SLOT(save_as_register_clicked()) ); connect(ui->actionNew_Shortcut, SIGNAL(triggered()), this, SLOT(SetupNewFile()) ); connect(ui->actionOpen_File, SIGNAL(triggered()), this, SLOT(open_file_clicked()) ); connect(ui->actionOpen_Directory, SIGNAL(triggered()), this, SLOT(open_dir_clicked()) ); connect(ui->line_xdg_command, SIGNAL(editingFinished()), this, SLOT(xdgvaluechanged()) ); connect(ui->line_xdg_comment, SIGNAL(editingFinished()), this, SLOT(xdgvaluechanged()) ); connect(ui->line_xdg_icon, SIGNAL(textChanged(QString)), this, SLOT(ReloadAppIcon()) ); connect(ui->tool_xdg_getCommand, SIGNAL(clicked()), this, SLOT(getXdgCommand()) ); connect(ui->line_xdg_name, SIGNAL(editingFinished()), this, SLOT(xdgvaluechanged()) ); connect(ui->line_xdg_wdir, SIGNAL(editingFinished()), this, SLOT(xdgvaluechanged()) ); connect(ui->check_xdg_useTerminal, SIGNAL(clicked()), this, SLOT(xdgvaluechanged()) ); connect(ui->check_xdg_startupNotify, SIGNAL(clicked()), this, SLOT(xdgvaluechanged()) ); connect(this, SIGNAL(folder_size_changed(quint64, quint64, quint64, bool)), this, SLOT(refresh_folder_size(quint64, quint64, quint64, bool))); } //UI Buttons void MainUI::closeApplication(){ terminate_thread = true; if(ui->actionSave_Shortcut->isEnabled()){ //Still have unsaved changes //TO-DO - prompt for whether to save the changes } this->close(); } void MainUI::save_clicked(){ //Save all the xdg values into the structure QString filePath = INFO->filePath(); if( !filePath.isEmpty() && !INFO->isDesktopFile() ){ return; } if(filePath.isEmpty() || !canwrite){ //Need to prompt for where to save the file and what to call it QString appdir = QString(getenv("XDG_DATA_HOME"))+"/applications/"; if(!QFile::exists(appdir)){ QDir dir; dir.mkpath(appdir); } filePath = QFileDialog::getSaveFileName(this, tr("Save Application File"), appdir, tr("XDG Shortcuts (*.desktop)") ); if(filePath.isEmpty()){ return; } if(!filePath.endsWith(".desktop")){ filePath.append(".desktop"); } } //qDebug() << " -Try Saving File:" << filePath; bool saved = saveFile(filePath); //qDebug() << "File Saved:" << saved; ui->actionSave_Shortcut->setEnabled( !saved ); if(saved){ //Re-load the file info LoadFile(filePath); } } void MainUI::save_as_local_clicked(){ QString filePath = QFileDialog::getSaveFileName(this, tr("Save Application File"), QDir::homePath(), tr("XDG Shortcuts (*.desktop)") ); if(filePath.isEmpty()){ return; } if(!filePath.endsWith(".desktop")){ filePath.append(".desktop"); } //qDebug() << " -Try Saving File:" << filePath; bool saved = saveFile(filePath); //qDebug() << "File Saved:" << saved; ui->actionSave_Shortcut->setEnabled( !saved ); if(saved){ //Re-load the file info LoadFile(filePath); } } void MainUI::save_as_register_clicked(){ QString appdir = QString(getenv("XDG_DATA_HOME"))+"/applications/"; if(!QFile::exists(appdir)){ QDir dir; dir.mkpath(appdir); } QString filePath = QFileDialog::getSaveFileName(this, tr("Save Application File"), appdir, tr("XDG Shortcuts (*.desktop)") ); if(filePath.isEmpty()){ return; } if(!filePath.endsWith(".desktop")){ filePath.append(".desktop"); } //qDebug() << " -Try Saving File:" << filePath; bool saved = saveFile(filePath); //qDebug() << "File Saved:" << saved; ui->actionSave_Shortcut->setEnabled( !saved ); if(saved){ //Re-load the file info LoadFile(filePath); } } void MainUI::open_dir_clicked(){ QString path = findOpenDirFile(true); //directory only if(path.isEmpty()){ return; } LoadFile(path, ""); } void MainUI::open_file_clicked(){ QString path = findOpenDirFile(false); //files only if(path.isEmpty()){ return; } LoadFile(path, ""); } void MainUI::getXdgCommand(QString prev){ //Find a binary to run QString dir = prev; //start with the previous attempt (if there was one) if(dir.isEmpty()){ ui->line_xdg_command->text(); }//then try current selection if(dir.isEmpty()){ dir = LOS::AppPrefix()+"bin"; } //then open the application binaries directory QString file = QFileDialog::getOpenFileName(this, tr("Select a binary"), dir ); if(file.isEmpty()){ return; } //cancelled if(!LUtils::isValidBinary(file)){ QMessageBox::warning(this, tr("Error"), tr("Invalid selection: Not a valid executable")); getXdgCommand(file); return; } ui->line_xdg_command->setText(file); xdgvaluechanged(); } void MainUI::on_tool_xdg_getDir_clicked(){ //Find a directory QString dir = ui->line_xdg_wdir->text(); if(dir.isEmpty()){ dir = QDir::homePath(); } dir = QFileDialog::getExistingDirectory(this, tr("Select a directory"), dir); if(dir.isEmpty()){ return; } //cancelled ui->line_xdg_wdir->setText(dir); xdgvaluechanged(); } void MainUI::on_push_xdg_getIcon_clicked(){ //Find an image file QString dir = ui->push_xdg_getIcon->whatsThis(); //then try current selection if(dir.isEmpty()){ dir = QDir::homePath(); } //Get the known file extensions QStringList ext = LUtils::imageExtensions(); for(int i=0; iline_xdg_icon->setText(file); ReloadAppIcon(); xdgvaluechanged(); } //XDG Value Changed bool MainUI::checkXDGValidity(){ XDGDesktop tmp; tmp.type = XDGDesktop::APP; //make this adjustable later (GUI radio buttons?) tmp.name = ui->line_xdg_name->text(); tmp.genericName = ui->line_xdg_name->text().toLower(); tmp.comment = ui->line_xdg_comment->text(); tmp.icon = ui->line_xdg_icon->text(); //Now do the type-specific fields if(tmp.type == XDGDesktop::APP){ tmp.exec = ui->line_xdg_command->text(); tmp.tryexec = ui->line_xdg_command->text().section(" ",0,0); //use the first word/binary for the existance check tmp.path = ui->line_xdg_wdir->text(); //working dir/path tmp.useTerminal = ui->check_xdg_useTerminal->isChecked(); tmp.startupNotify = ui->check_xdg_startupNotify->isChecked(); }else if(tmp.type==XDGDesktop::LINK){ tmp.url = ui->line_xdg_wdir->text(); //we re-used this field } bool valid = tmp.isValid(); ui->label_xdg_statusicon->setPixmap( LXDG::findIcon( valid ? "dialog-ok" : "dialog-cancel", "").pixmap(32,32) ); ui->label_xdg_status->setText( valid ? tr("Valid Settings") : tr("Invalid Settings") ); return tmp.isValid(); } void MainUI::xdgvaluechanged(){ //qDebug() << "xdgvaluechanged"; if( INFO->isDesktopFile() || INFO->filePath().isEmpty() ){ bool valid = checkXDGValidity(); //Compare the current UI values to the file values ui->menuSave_As->setEnabled(valid); ui->actionSave_Shortcut->setEnabled(canwrite && valid); //assume changed at this point }else{ ui->actionSave_Shortcut->setEnabled(false); } } void MainUI::refresh_folder_size(quint64 size, quint64 files, quint64 folders, bool finished) { if(finished) ui->label_file_size->setText( LUtils::BytesToDisplaySize( size ) + " -- " + tr(" Folders: ") + QString::number(folders) + " / " + tr("Files: ") + QString::number(files) ); else ui->label_file_size->setText( LUtils::BytesToDisplaySize( size ) + " -- " + tr(" Folders: ") + QString::number(folders) + " / " + tr("Files: ") + QString::number(files) + tr(" Calculating..." )); }