diff options
Diffstat (limited to 'src-qt5/desktop-utils')
34 files changed, 1316 insertions, 257 deletions
diff --git a/src-qt5/desktop-utils/lumina-archiver/MainUI.cpp b/src-qt5/desktop-utils/lumina-archiver/MainUI.cpp index 43020309..9b77a477 100644 --- a/src-qt5/desktop-utils/lumina-archiver/MainUI.cpp +++ b/src-qt5/desktop-utils/lumina-archiver/MainUI.cpp @@ -52,7 +52,7 @@ MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI){ ui->action_Open->setShortcut(tr("CTRL+O")); ui->action_Quit->setShortcut(tr("CTRL+Q")); ui->actionExtract_All->setShortcut(tr("CTRL+E")); - + ui->progressBar->setVisible(false); ui->label_progress->setVisible(false); ui->label_progress_icon->setVisible(false); @@ -75,39 +75,13 @@ void MainUI::LoadArguments(QStringList args){ for(int i=0; i<args.length(); i++){ if(args[i]=="--burn-img"){ burnIMG = true; continue; } if(args[i]=="--ax"){ autoExtract = true; continue; } - /*i++; - QFileInfo filename(args[i]); - QDir filedir = filename.canonicalPath(); - QString newdir = filename.completeBaseName(); - filedir.mkpath(newdir); - dir = newdir; - qDebug() << "MAINUI - archivefile = " << args[i]; - qDebug() << "MAINUI - filedir = " << filedir; - qDebug() << "MAINUI - newdir = " << newdir; - qDebug() << "MAINUI - dir = " << dir; - BACKEND->loadFile(args[i]); - qDebug () << "MAINUI - File should have loaded"; - //add in a delay in case i'm hitting a race condition - QTime waitTime= QTime::currentTime().addSecs(2); - while (QTime::currentTime() < waitTime) - QCoreApplication::processEvents(QEventLoop::AllEvents, 100); - //things should have settled, now trigger extraction - if(autoExtract){ - ui->label_progress->setText(tr("Extracting...")); - autoextractFiles(); - qDebug () << "MAINUI - Extraction should have started"; - } - //now quit - //QCoreApplication::quit(); - return; - }*/ if(QFile::exists(args[i])){ ui->label_progress->setText(tr("Opening Archive...")); - if(autoExtract){ - connect(BACKEND, SIGNAL(FileLoaded()), this, SLOT(autoextractFiles()) ); + if(autoExtract){ + connect(BACKEND, SIGNAL(FileLoaded()), this, SLOT(autoextractFiles()) ); connect(BACKEND, SIGNAL(ExtractSuccessful()), this, SLOT(close()) ); } - BACKEND->loadFile(args[i]); + BACKEND->loadFile(args[i]); ui->actionUSB_Image->setEnabled(args[i].simplified().endsWith(".img")); if(burnIMG){ BurnImgToUSB(); } //Go ahead and launch the burn dialog right away break; @@ -140,10 +114,9 @@ QTreeWidgetItem* MainUI::findItem(QString path, QTreeWidgetItem *start){ }else{ for(int i=0; i<start->childCount(); i++){ if(start->child(i)->whatsThis(0) == path){ return start->child(i); } - else if(path.startsWith(start->child(i)->whatsThis(0)+"/")){ return findItem(path, start->child(i)); } + else if(path.startsWith(start->child(i)->whatsThis(0)+"/")){ return findItem(path, start->child(i)); } } } - //qDebug() << "Could not find item:" << path; return 0; //nothing found } @@ -272,18 +245,11 @@ void MainUI::extractFiles(){ } void MainUI::autoextractFiles(){ - disconnect(BACKEND, SIGNAL(fileLoaded()), this, SLOT(autoextractFiles()) ); + disconnect(BACKEND, SIGNAL(FileLoaded()), this, SLOT(autoextractFiles()) ); QString dir = BACKEND->currentFile().section("/",0,-2); //parent directory of the archive - //QFileDialog::getExistingDirectory(this, tr("Extract Into Directory"), QDir::homePath() ); if(dir.isEmpty()){ return; } - //add in a delay in case i'm hitting a race condition - /*qDebug() << "void MainUI::autoextractFiles() has started"; - QTime waitTime= QTime::currentTime().addSecs(2); - while (QTime::currentTime() < waitTime) - QCoreApplication::processEvents(QEventLoop::AllEvents, 100);*/ ui->label_progress->setText(tr("Extracting...")); BACKEND->startExtract(dir, true); -// QApplication::quit(); } void MainUI::extractSelection(){ @@ -312,7 +278,6 @@ void MainUI::UpdateTree(){ files.sort(); //Remove any entries for file no longer in the archive bool changed = cleanItems(files); - //qDebug() << "Found Files:" << files; for(int i=0; i<files.length(); i++){ if(0 != findItem(files[i]) ){ continue; } //already in the tree widget QString mime = LXDG::findAppMimeForFile(files[i].section("/",-1), false); //first match only diff --git a/src-qt5/desktop-utils/lumina-archiver/TarBackend.cpp b/src-qt5/desktop-utils/lumina-archiver/TarBackend.cpp index 226da9f1..c0d3b03e 100644 --- a/src-qt5/desktop-utils/lumina-archiver/TarBackend.cpp +++ b/src-qt5/desktop-utils/lumina-archiver/TarBackend.cpp @@ -30,14 +30,11 @@ void Backend::loadFile(QString path){ qDebug() << "void Backend::loadFile(QString path) has started"; qDebug() << "Loading Archive:" << path; filepath = path; - //qDebug () << "BACKEND LOAD- " << "path = " << path; - //qDebug () << "BACKEND LOAD- " << "filepath = " << filepath; tmpfilepath = filepath.section("/",0,-2)+"/"+".tmp_larchiver_"+filepath.section("/",-1); flags.clear(); flags << "-f" << filepath; //add the actual archive path if(QFile::exists(path)){ startList(); qDebug () << "BACKEND LOAD startList has started";} else{ contents.clear(); emit ProcessFinished(true, ""); } - //qDebug () << "BACKEND LOAD COMPLETE"; } bool Backend::canModify(){ @@ -108,8 +105,8 @@ void Backend::startAdd(QStringList paths){ args << paths; if(QFile::exists(filepath)){ //append to existing args.replaceInStrings(filepath, tmpfilepath); - args<< "@"+filepath; - } + args<< "@"+filepath; + } STARTING=true; PROC.start("tar", args); } @@ -120,21 +117,17 @@ void Backend::startRemove(QStringList paths){ QStringList args; args << "-c" << "-a"; args << flags; - args.replaceInStrings(filepath, tmpfilepath); + args.replaceInStrings(filepath, tmpfilepath); //Add the include rules for all the files we want to keep (no exclude option in "tar") for(int i=0; i<paths.length(); i++){ args << "--exclude" << paths[i]; } - args<< "@"+filepath; + args<< "@"+filepath; STARTING=true; PROC.start("tar", args); } void Backend::startExtract(QString path, bool overwrite, QString file){ - qDebug () << "BACKEND startExtract -" << "void Backend::startExtract(QString path, bool overwrite, QString file) has started"; - qDebug () << "BACKEND startExtract -" << "path = " << path; - qDebug () << "BACKEND startExtract -" << "overwrite =" << overwrite ; - qDebug () << "BACKEND startExtract -" << "file =" << file; startExtract(path, overwrite, QStringList() << file); //overload for multi-file function } @@ -179,7 +172,7 @@ void Backend::parseLines(QStringList lines){ if(info.startsWith("x ") && filepath.endsWith(".zip")){ //ZIP archives do not have all the extra information - just filenames while(info.length()>2){ info[1]=info[1]+" "+info[2]; } - QString file = info[1]; + QString file = info[1]; QString perms = ""; if(file.endsWith("/")){ perms = "d"; file.chop(1); } contents.insert(file, QStringList() << perms << "-1" <<""); //Save the [perms, size, linkto ] @@ -187,7 +180,7 @@ void Backend::parseLines(QStringList lines){ else if(info.length()<9){ continue; } //invalid line //TAR Archive parsing while(info.length()>9){ info[8] = info[8]+" "+info[9]; info.removeAt(9); } //Filename has spaces in it - QString file = info[8]; + QString file = info[8]; if(file.endsWith("/")){ file.chop(1); } QString linkto; //See if this file has the "link to" or "->" notation @@ -241,9 +234,14 @@ void Backend::procFinished(int retcode, QProcess::ExitStatus){ QProcess::startDetached("xdg-open \""+path+"\""); }else{ //Multi-file extract - open the dir instead - QProcess::startDetached("xdg-open \""+ args.last()+"\""); //just extracted to a dir - open it now + QString dir = args.last(); + //Check to see if tar extracted into a new subdir it just created + if(QFile::exists(dir+"/"+filepath.section("/",-1).section(".",0,0) ) ){ + dir = dir+"/"+filepath.section("/",-1).section(".",0,0); + } + QProcess::startDetached("xdg-open \""+ dir+"\""); //just extracted to a dir - open it now } - + }else if(args.contains("-c") && QFile::exists(tmpfilepath)){ if(retcode==0){ QFile::remove(filepath); @@ -260,7 +258,7 @@ void Backend::procFinished(int retcode, QProcess::ExitStatus){ } void Backend::processData(){ - //Read the process + //Read the process static QString data; QString read = data+PROC.readAllStandardOutput(); if(read.endsWith("\n")){ data.clear(); } diff --git a/src-qt5/desktop-utils/lumina-archiver/TarBackend.h b/src-qt5/desktop-utils/lumina-archiver/TarBackend.h index 271efa42..3eb4eb53 100644 --- a/src-qt5/desktop-utils/lumina-archiver/TarBackend.h +++ b/src-qt5/desktop-utils/lumina-archiver/TarBackend.h @@ -37,10 +37,10 @@ public: void startRemove(QStringList paths); void startExtract(QString path, bool overwrite, QString file=""); //path to dir, overwrite, optional file to extract (everything otherwise) void startExtract(QString path, bool overwrite, QStringList files); - + void startViewFile(QString path); - //Special process + //Special process public slots: private: diff --git a/src-qt5/desktop-utils/lumina-calculator/mainUI.cpp b/src-qt5/desktop-utils/lumina-calculator/mainUI.cpp index a0b1416e..a3e55dda 100644 --- a/src-qt5/desktop-utils/lumina-calculator/mainUI.cpp +++ b/src-qt5/desktop-utils/lumina-calculator/mainUI.cpp @@ -60,7 +60,7 @@ mainUI::mainUI() : QMainWindow(), ui(new Ui::mainUI()){ escShortcut = new QShortcut(Qt::Key_Escape, this); connect(escShortcut, SIGNAL(activated()), this, SLOT(clear_calc()) ); quitShortcut = new QShortcut(Qt::CTRL + Qt::Key_Q, this); - connect(quitShortcut, SIGNAL(activated()), this, SLOT(on_quitShortcut_Triggered()) ); + connect(quitShortcut, SIGNAL(activated()), this, SLOT(quitShortcut_Triggered()) ); } mainUI::~mainUI(){ @@ -169,7 +169,7 @@ void mainUI::copy_to_clipboard(QListWidgetItem *it){ void mainUI::checkInput(const QString &str){ if(str.length()==1 && ui->list_results->count()>0){ - if(OPS.contains(str)){ + if(OPS.contains(str)){ QString lastresult = ui->list_results->item( ui->list_results->count()-1)->text().section("]",0,0).section("[",-1).simplified(); ui->line_eq->setText( lastresult+str); } @@ -216,8 +216,8 @@ double mainUI::performSciOperation(QString func, double arg){ else if(func=="sinh"){ return ::sinh(arg); } else if(func=="cosh"){ return ::cosh(arg); } else if(func=="tanh"){ return ::tanh(arg); } - else{ - qDebug() << "Unknown Scientific Function:" << func; + else{ + qDebug() << "Unknown Scientific Function:" << func; return BADVALUE; } //Special cases: @@ -292,7 +292,7 @@ double mainUI::strToNumber(QString str){ for(int i=0; i<symbols.length(); i++){ int tmp = str.indexOf(symbols[i]); while(tmp==0 || (tmp>0 && str[tmp-1].toLower()=='e') ){ tmp = str.indexOf(symbols[i], tmp+1); } //catch scientific notation - if(sym < tmp){ + if(sym < tmp){ //qDebug() << " - found:" << tmp << sym; sym = tmp; } @@ -312,7 +312,7 @@ double mainUI::strToNumber(QString str){ //qDebug() << " - Found Number:" << str;// << str.toDouble(); if(str=="\u03C0"){ return PI; } //else if(str.endsWith("\u03C0")){ - //return performOperation( strToNumber(str.section("\u03C0",0,-2)), PI, '*'); + //return performOperation( strToNumber(str.section("\u03C0",0,-2)), PI, '*'); else if(str.contains("\u03C0")){ qDebug() << " Has Pi:" << str.count("\u03C0"); //Pi is mixed into the number - need to multiply it all out @@ -336,7 +336,7 @@ QString mainUI::getHistory(int number){ QString ans = ui->list_results->item(number-1)->text().section("=",0,0).section("]",-1).simplified(); QString eq = ui->list_results->item(number-1)->text().section("[",-1).section("]",0,0).simplified(); //See if the text answer is accurate enough (does not look rounded) - if(ans.length()<7){ + if(ans.length()<7){ return ("("+ans+")"); //short enough answer that it was probably not rounded }else{ //need to re-calculate the last equation instead for exact result @@ -344,7 +344,6 @@ QString mainUI::getHistory(int number){ } } -void mainUI::on_quitShortcut_Triggered(){ +void mainUI::quitShortcut_Triggered(){ QApplication::quit(); } - diff --git a/src-qt5/desktop-utils/lumina-calculator/mainUI.h b/src-qt5/desktop-utils/lumina-calculator/mainUI.h index 308eab30..19077ca7 100644 --- a/src-qt5/desktop-utils/lumina-calculator/mainUI.h +++ b/src-qt5/desktop-utils/lumina-calculator/mainUI.h @@ -54,7 +54,7 @@ private slots: void saveHistory(); - void on_quitShortcut_Triggered(); + void quitShortcut_Triggered(); private: Ui::mainUI *ui; diff --git a/src-qt5/desktop-utils/lumina-fm/Browser.cpp b/src-qt5/desktop-utils/lumina-fm/Browser.cpp index b7eb9709..010196a4 100644 --- a/src-qt5/desktop-utils/lumina-fm/Browser.cpp +++ b/src-qt5/desktop-utils/lumina-fm/Browser.cpp @@ -20,7 +20,7 @@ Browser::Browser(QObject *parent) : QObject(parent){ showHidden = false; showThumbs = false; imageFormats = LUtils::imageExtensions(false); //lowercase suffixes - connect(this, SIGNAL(threadDone(QString, QByteArray)), this, SLOT(futureFinished(QString, QByteArray))); //will always be between different threads + connect(this, SIGNAL(threadDone(QString, QImage)), this, SLOT(futureFinished(QString, QImage))); //will always be between different threads } Browser::~Browser(){ @@ -53,20 +53,25 @@ bool Browser::showingThumbnails(){ // PRIVATE void Browser::loadItem(QString info, Browser *obj){ //qDebug() << "LoadItem:" << info; - QByteArray bytes; + QImage pix; if(imageFormats.contains(info.section(".",-1).toLower()) ){ QFile file(info); if(file.open(QIODevice::ReadOnly)){ - bytes = file.readAll(); + QByteArray bytes = file.readAll(); file.close(); + pix.loadFromData(bytes); + if(bytes.size() > (512*1024) ){ //more than 512 KB + pix = pix.scaled(256,256, Qt::KeepAspectRatio, Qt::SmoothTransformation); + } } } + //qDebug() << " - done with item:" << info; - obj->emit threadDone(info, bytes); + obj->emit threadDone(info, pix); } QIcon Browser::loadIcon(QString icon){ - if(!mimeIcons.contains(icon)){ + if(!mimeIcons.contains(icon)){ mimeIcons.insert(icon, LXDG::findIcon(icon, "unknown")); } @@ -76,7 +81,7 @@ QIcon Browser::loadIcon(QString icon){ // PRIVATE SLOTS void Browser::fileChanged(QString file){ - if(file.startsWith(currentDir+"/") ){ + if(file.startsWith(currentDir+"/") ){ if(QFile::exists(file) ){ QtConcurrent::run(this, &Browser::loadItem, file, this); } //file modified but not removed else{ QTimer::singleShot(0, this, SLOT(loadDirectory()) ); } //file removed - need to update entire dir }else if(file==currentDir){ QTimer::singleShot(0, this, SLOT(loadDirectory()) ); } @@ -87,20 +92,20 @@ void Browser::dirChanged(QString dir){ else if(dir.startsWith(currentDir)){ QtConcurrent::run(this, &Browser::loadItem, dir, this ); } } -void Browser::futureFinished(QString name, QByteArray icon){ +void Browser::futureFinished(QString name, QImage icon){ //Note: this will be called once for every item that loads qDebug() << "Future Finished:" << name; QIcon ico; LFileInfo info(name); - if(!icon.isEmpty()){ + if(!icon.isNull()){ //qDebug() << " -- Data:"; - QPixmap pix; - if(pix.loadFromData(icon) ){ ico.addPixmap(pix); } + QPixmap pix = QPixmap::fromImage(icon); + ico.addPixmap(pix); }else if(info.isDir()){ //qDebug() << " -- Folder:"; - ico = loadIcon("folder"); + ico = loadIcon("folder"); } - if(ico.isNull()){ + if(ico.isNull()){ //qDebug() << " -- MimeType:" << info.fileName() << info.mimetype(); ico = loadIcon(info.iconfile()); } @@ -116,8 +121,8 @@ void Browser::loadDirectory(QString dir){ qDebug() << "Load Directory" << dir; if(currentDir != dir){ //let the main widget know to clear all current items (completely different dir) oldFiles.clear(); - emit clearItems(); - } + emit clearItems(); + } currentDir = dir; //save this for later //clean up the watcher first QStringList watched; watched << watcher->files() << watcher->directories(); @@ -141,7 +146,7 @@ void Browser::loadDirectory(QString dir){ QtConcurrent::run(this, &Browser::loadItem, path, this); }else{ //No special icon loading - just skip the file read step - futureFinished(path, QByteArray()); //loadItem(path, this); + futureFinished(path, QImage()); //loadItem(path, this); } } watcher->addPath(directory.absolutePath()); diff --git a/src-qt5/desktop-utils/lumina-fm/Browser.h b/src-qt5/desktop-utils/lumina-fm/Browser.h index b96a7281..40e98753 100644 --- a/src-qt5/desktop-utils/lumina-fm/Browser.h +++ b/src-qt5/desktop-utils/lumina-fm/Browser.h @@ -46,7 +46,6 @@ private: bool showHidden, showThumbs; QStringList imageFormats, oldFiles; QHash<QString, QIcon> mimeIcons; //cache for quickly re-using QIcons - void loadItem(QString info, Browser *obj); //this is the main loader class - multiple instances each run in a separate thread QIcon loadIcon(QString icon); //simplification for using/populating the mimIcons cache @@ -55,7 +54,7 @@ private slots: void fileChanged(QString); //tied into the watcher - for file change notifications void dirChanged(QString); // tied into the watcher - for new/removed files in the current dir - void futureFinished(QString, QByteArray); + void futureFinished(QString, QImage); public slots: void loadDirectory(QString dir = ""); @@ -70,7 +69,7 @@ signals: void itemsLoading(int); //number of items which are getting loaded //Internal signal for the alternate threads - void threadDone(QString, QByteArray); + void threadDone(QString, QImage); }; #endif diff --git a/src-qt5/desktop-utils/lumina-fm/MainUI.cpp b/src-qt5/desktop-utils/lumina-fm/MainUI.cpp index 9962a4bf..73d1420a 100644 --- a/src-qt5/desktop-utils/lumina-fm/MainUI.cpp +++ b/src-qt5/desktop-utils/lumina-fm/MainUI.cpp @@ -22,10 +22,10 @@ MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI){ //qRegisterMetaType<QFileInfoList>("QFileInfoList"); qRegisterMetaType< LFileInfoList >("LFileInfoList"); //just to silence/fix some Qt connect warnings in QtConcurrent - //qRegisterMetaType< QVector<int> >("QVector<int>"); + //qRegisterMetaType< QVector<int> >("QVector<int>"); //qRegisterMetaType< QList<QPersistentModelIndex> >("QList<QPersistentModelIndex>"); waitingToClose = false; - + ui->setupUi(this); if(DEBUG){ qDebug() << "Initilization:"; } settings = LUtils::openSettings("lumina-desktop", "lumina-fm", this); @@ -35,7 +35,7 @@ QSize orig = settings->value("preferences/MainWindowSize", QSize()).toSize(); if(!orig.isEmpty() && orig.isValid()){ //Make sure the old size is larger than the default size hint if(orig.width() < this->sizeHint().width()){ orig.setWidth(this->sizeHint().width()); } - if(orig.height() < this->sizeHint().height()){ orig.setHeight(this->sizeHint().height()); } + if(orig.height() < this->sizeHint().height()){ orig.setHeight(this->sizeHint().height()); } //Also ensure the old size is smaller than the current screen size QSize screen = QApplication::desktop()->availableGeometry(this).size(); if(orig.width() > screen.width()){ orig.setWidth(screen.width()); } @@ -94,6 +94,7 @@ QSize orig = settings->value("preferences/MainWindowSize", QSize()).toSize(); nextTabRShort = new QShortcut( QKeySequence(tr("Shift+Right")), this); togglehiddenfilesShort = new QShortcut( QKeySequence(tr("Ctrl+H")), this); focusDirWidgetShort = new QShortcut( QKeySequence(tr("Ctrl+L")), this); + toggledirtreepaneShort = new QShortcut( QKeySequence(tr("Ctrl+P")), this); //Finish loading the interface workThread->start(); @@ -134,7 +135,7 @@ void MainUI::OpenDirs(QStringList dirs){ if(DEBUG){ qDebug() << "Open Directory:" << dirs[i]; } ///Get a new Unique ID int id = 0; - for(int j=0; j<DWLIST.length(); j++){ + for(int j=0; j<DWLIST.length(); j++){ if(DWLIST[j]->id().section("-",1,1).toInt() >= id){ id = DWLIST[j]->id().section("-",1,1).toInt()+1; } } //Create the new DirWidget @@ -157,7 +158,7 @@ void MainUI::OpenDirs(QStringList dirs){ connect(DW, SIGNAL(PasteFiles(QString,QStringList)), this, SLOT(PasteFiles(QString, QStringList)) ); connect(DW, SIGNAL(CloseBrowser(QString)), this, SLOT(CloseBrowser(QString)) ); connect(DW, SIGNAL(TabNameChanged(QString,QString)), this, SLOT(TabNameChanged(QString, QString)) ); - //Now create the tab for this + //Now create the tab for this //if(radio_view_tabs->isChecked()){ int index = tabBar->addTab( LXDG::findIcon("folder-open",""), dirs[i].section("/",-1) ); tabBar->setTabWhatsThis( index, "DW-"+QString::number(id) ); @@ -175,12 +176,13 @@ void MainUI::OpenDirs(QStringList dirs){ tabBar->setCurrentIndex(index); } }*/ - + //Initialize the widget with the proper settings DW->setShowDetails(radio_view_details->isChecked()); DW->setThumbnailSize(settings->value("iconsize", 32).toInt()); DW->showHidden( ui->actionView_Hidden_Files->isChecked() ); DW->showThumbnails( ui->actionShow_Thumbnails->isChecked() ); + DW->showDirTreePane( ui->actionView_showDirTreePane->isChecked() ); //Now load the directory DW->ChangeDir(dirs[i]); //kick off loading the directory info } @@ -200,7 +202,7 @@ void MainUI::OpenDirs(QStringList dirs){ void MainUI::setupIcons(){ this->setWindowIcon( LXDG::findIcon("Insight-FileManager","") ); - + //Setup all the icons using libLumina // File menu ui->actionNew_Window->setIcon( LXDG::findIcon("window-new","") ); @@ -254,6 +256,8 @@ void MainUI::setupConnections(){ connect(nextTabRShort, SIGNAL(activated()), this, SLOT( nextTab() ) ); connect(togglehiddenfilesShort, SIGNAL(activated()), this, SLOT( togglehiddenfiles() ) ); connect(focusDirWidgetShort, SIGNAL(activated()), this, SLOT( focusDirWidget() ) ); + connect(toggledirtreepaneShort, SIGNAL(activated()), this, SLOT( toggleDirTreePane() ) ); + } void MainUI::focusDirWidget() @@ -270,6 +274,14 @@ void MainUI::togglehiddenfiles() on_actionView_Hidden_Files_triggered(); } +void MainUI::toggleDirTreePane() +{ + //change setChecked to inverse value + ui->actionView_Hidden_Files->setChecked( !settings->value("showdirtree", true).toBool() ); + // then trigger function + on_actionView_showDirTreePane_triggered(); +} + void MainUI::loadSettings(){ //Note: make sure this is run after all the UI elements are created and connected to slots // but before the first directory gets loaded @@ -277,6 +289,9 @@ void MainUI::loadSettings(){ on_actionView_Hidden_Files_triggered(); //make sure to update the models too ui->actionShow_Thumbnails->setChecked( settings->value("showthumbnails",true).toBool()); on_actionShow_Thumbnails_triggered(); //make sure to update models too + ui->actionView_showDirTreePane->setChecked( settings->value("showdirtree", false).toBool()); + on_actionView_showDirTreePane_triggered(); //make sure to update the models too + //ui->actionShow_Action_Buttons->setChecked(settings->value("showactions", true).toBool() ); //on_actionShow_Action_Buttons_triggered(); //make sure to update the UI //ui->actionShow_Thumbnails->setChecked( settings->value("showthumbnails", true).toBool() ); @@ -289,7 +304,7 @@ void MainUI::loadSettings(){ //bool usetabs = (settings->value("groupmode","tabs").toString()=="tabs"); //if(usetabs){ radio_view_tabs->setChecked(true); } // else{ radio_view_cols->setChecked(true); } - + } void MainUI::RebuildBookmarksMenu(){ @@ -344,7 +359,7 @@ void MainUI::RebuildDeviceMenu(){ //Add filesystem type to the label label = QString(tr("%1 (Type: %2)")).arg(label, fs); } - QAction *act = new QAction(label,this); + QAction *act = new QAction(label,this); act->setWhatsThis(path); //full path to mountpoint act->setToolTip( QString(tr("Filesystem: %1")).arg( devs[i].section("::::",1,1) ) ); //Now set the appropriate icon @@ -365,7 +380,7 @@ DirWidget* MainUI::FindActiveBrowser(){ //Get the current tab ID to start with QString cur = tabBar->tabWhatsThis(tabBar->currentIndex()); //if(cur.startsWith("#")){ cur.clear(); } //multimedia/player tab open - + if(DWLIST.length()==1){ //Only 1 browser open - use it curB = DWLIST[0]; @@ -382,7 +397,6 @@ DirWidget* MainUI::FindActiveBrowser(){ for(int i=0; i<DWLIST.length(); i++){ if(DWLIST[i]->isAncestorOf(focus)){ curB = DWLIST[i]; break; } //This browser has focus } - }else{ //Non-Browser in focus - use the fallback below } @@ -476,6 +490,14 @@ void MainUI::on_actionView_Hidden_Files_triggered(){ } +void MainUI::on_actionView_showDirTreePane_triggered(){ + //worker->showdirtree = ui->actionView_showDirTreePane->isChecked(); + settings->setValue("showdirtree", ui->actionView_showDirTreePane->isChecked()); +//Re-load the current browsers + +} + + /*void MainUI::on_actionShow_Action_Buttons_triggered(){ bool show = ui->actionShow_Action_Buttons->isChecked(); settings->setValue("showactions", show); diff --git a/src-qt5/desktop-utils/lumina-fm/MainUI.h b/src-qt5/desktop-utils/lumina-fm/MainUI.h index 9f542ea9..84ab5a64 100644 --- a/src-qt5/desktop-utils/lumina-fm/MainUI.h +++ b/src-qt5/desktop-utils/lumina-fm/MainUI.h @@ -91,7 +91,7 @@ private: bool waitingToClose; QSettings *settings; - QShortcut *nextTabLShort, *nextTabRShort, *togglehiddenfilesShort, *focusDirWidgetShort; + QShortcut *nextTabLShort, *nextTabRShort, *togglehiddenfilesShort, *focusDirWidgetShort, *toggledirtreepaneShort; //QCompleter *dirCompleter; //Simplification Functions @@ -126,8 +126,9 @@ private slots: void on_actionDelete_Selection_triggered();*/ void on_actionRefresh_triggered(); void on_actionView_Hidden_Files_triggered(); + void on_actionView_showDirTreePane_triggered(); //void on_actionShow_Action_Buttons_triggered(); - void on_actionShow_Thumbnails_triggered(); + void on_actionShow_Thumbnails_triggered(); void goToBookmark(QAction*); void goToDevice(QAction*); void viewModeChanged(bool); @@ -148,6 +149,7 @@ private slots: //Other Shortcuts void togglehiddenfiles(); + void toggleDirTreePane(); void focusDirWidget(); //Backend Info passing diff --git a/src-qt5/desktop-utils/lumina-fm/MainUI.ui b/src-qt5/desktop-utils/lumina-fm/MainUI.ui index 189b563f..744f31a3 100644 --- a/src-qt5/desktop-utils/lumina-fm/MainUI.ui +++ b/src-qt5/desktop-utils/lumina-fm/MainUI.ui @@ -69,7 +69,7 @@ <x>0</x> <y>0</y> <width>567</width> - <height>367</height> + <height>359</height> </rect> </property> <layout class="QHBoxLayout" name="BrowserLayout"> @@ -106,7 +106,7 @@ <x>0</x> <y>0</y> <width>567</width> - <height>24</height> + <height>28</height> </rect> </property> <widget class="QMenu" name="menuFile"> @@ -420,6 +420,20 @@ <string>Clone Repository</string> </property> </action> + <action name="actionView_showDirTreePane"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Show Directory Tree Window</string> + </property> + <property name="toolTip"> + <string>Show Directory Tree Pane</string> + </property> + <property name="shortcut"> + <string>Ctrl+P</string> + </property> + </action> </widget> <resources/> <connections/> diff --git a/src-qt5/desktop-utils/lumina-fm/lumina-fm.pro b/src-qt5/desktop-utils/lumina-fm/lumina-fm.pro index a98161f0..f7253e84 100644 --- a/src-qt5/desktop-utils/lumina-fm/lumina-fm.pro +++ b/src-qt5/desktop-utils/lumina-fm/lumina-fm.pro @@ -14,6 +14,7 @@ include(../../core/libLumina/LDesktopUtils.pri) #includes LUtils include(../../core/libLumina/LuminaXDG.pri) include(../../core/libLumina/LuminaSingleApplication.pri) include(../../core/libLumina/LuminaThemes.pri) +include(../../core/libLumina/ExternalProcess.pri) SOURCES += main.cpp \ MainUI.cpp \ diff --git a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.cpp b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.cpp index 293db823..6c2d4f35 100644 --- a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.cpp +++ b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.cpp @@ -17,10 +17,12 @@ #include <QScrollBar> #include <QSettings> #include <QtConcurrent/QtConcurrentRun> +#include <QFileSystemModel> #include <LuminaOS.h> #include <LuminaXDG.h> #include <LUtils.h> +#include <ExternalProcess.h> #include "../ScrollDialog.h" @@ -62,14 +64,28 @@ DirWidget::DirWidget(QString objID, QWidget *parent) : QWidget(parent), ui(new U 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()/3 << 2*this->width()/3); + 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 = 0; //not created yet + cNewMenu = cOpenMenu = cFModMenu = cFViewMenu = cOpenWithMenu = 0; //not created yet connect(contextMenu, SIGNAL(aboutToShow()), this, SLOT(UpdateContextMenu()) ); UpdateIcons(); - UpdateText(); + UpdateText(); createShortcuts(); createMenus(); } @@ -129,6 +145,25 @@ void DirWidget::setThumbnailSize(int px){ ui->tool_zoom_out->setEnabled(px >16); //lower limit on image sizes } +//==================== +// Folder Pane +//==================== + +void DirWidget::showDirTreePane(bool show){ + if(show !=showdirtree){ + showdirtree = show; + } +} + +bool DirWidget::showingDirTreePane(){ + return showdirtree; +} + +void DirWidget::on_folderViewPane_clicked(const QModelIndex &index){ + QString tPath = dirtreeModel->fileInfo(index).absoluteFilePath(); // get what was clicked + ChangeDir(tPath); +} + // ================ // PUBLIC SLOTS // ================ @@ -140,8 +175,8 @@ void DirWidget::LoadSnaps(QString basedir, QStringList snaps){ 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)); + 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(); @@ -151,12 +186,12 @@ void DirWidget::LoadSnaps(QString basedir, QStringList snaps){ } 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); + //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) + 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 @@ -183,10 +218,9 @@ void DirWidget::UpdateIcons(){ 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(){ @@ -199,36 +233,37 @@ void DirWidget::UpdateText(){ // 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); -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(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()) ); - + 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(){ @@ -260,6 +295,38 @@ void DirWidget::createMenus(){ cFModMenu->addSeparator(); cFModMenu->addAction(LXDG::findIcon("edit-delete",""), tr("Delete Selection"), this, SLOT(removeFiles()), kDel->key() ); */ + +//---------------------------------------------------// + /* + if(cOpenWithMenu==0){ cOpenWithMenu = new QMenu(this); } + else{ cOpenWithMenu->clear(); } + cOpenWithMenu->setTitle(tr("Open with...")); + cOpenWithMenu->setIcon( LXDG::findIcon("run-build-configure","") ); + XDGDesktopList applist; + applist.updateList(); + PREFAPPS = getPreferredApplications(); + //qDebug() << "Preferred Apps:" << PREFAPPS; + cOpenWithMenu->clear(); + //Now get the application mimetype for the file extension (if available) + QStringList mimetypes = LXDG::findAppMimeForFile(filePath, true).split("::::"); //use all mimetypes + //Now add all the detected applications + QHash< QString, QList<XDGDesktop*> > hash = LXDG::sortDesktopCats( applist.apps(false,true) ); + QStringList cat = hash.keys(); + cat.sort(); //sort alphabetically + for(int c=0; c<cat.length(); c++){ + QList<XDGDesktop*> app = hash[cat[c]]; + if(app.length()<1){ cOpenWithMenu =0; continue; } + for(int a=0; a<app.length(); a++){ + QString program = app[a]->filePath; + QStringList arguments; + arguments << "%u"; + QProcess *p = new QProcess(); + p->start(program, arguments); + + cOpenWithMenu->addAction(LXDG::findIcon(app[a]->icon), (app[a]->name), this, SLOT(p->start(program, arguments)) );}} + cOpenWithMenu->addAction(LXDG::findIcon("run-build-configure",""), tr("Other..."), this, SLOT(runWithFiles()) ); +*/ +//---------------------------------------------------// if(cFViewMenu==0){ cFViewMenu = new QMenu(this); } else{ cFViewMenu->clear(); } cFViewMenu->setTitle(tr("View Files...")); @@ -318,7 +385,7 @@ void DirWidget::on_slider_snap_valueChanged(int val){ //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){ + 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) ); @@ -378,12 +445,12 @@ void DirWidget::on_actionBack_triggered(){ } void DirWidget::on_actionUp_triggered(){ - QString dir = currentBrowser()->currentDirectory().section("/",0,-2); +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 + 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); } @@ -417,7 +484,7 @@ void DirWidget::on_actionSingleColumn_triggered(bool checked){ } void DirWidget::on_actionDualColumn_triggered(bool checked){ - if(!checked){ return; } + if(!checked){ return; } if(RCBW!=0){ return; } //nothing to do RCBW = new BrowserWidget("rc", this); ui->browser_layout->addWidget(RCBW); @@ -467,7 +534,7 @@ void DirWidget::fileProperties(){ 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++){ + for(int i=0; i<sel.length(); i++){ QProcess::startDetached("lumina-fileinfo \""+sel[i]+"\""); //use absolute paths } } @@ -489,18 +556,19 @@ void DirWidget::UpdateContextMenu(){ //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()) ); + 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->addSection(LXDG::findIcon("unknown",""), tr("File Operations")); // contextMenu->addMenu(cFModMenu); // cFModMenu->setEnabled(!sel.isEmpty() && canmodify); - if(!sel.isEmpty()){ + 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); @@ -513,12 +581,12 @@ void DirWidget::UpdateContextMenu(){ 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); + //Now add the general selection options + contextMenu->addSection(LXDG::findIcon("folder","inode/directory"), tr("Directory Operations")); + if(canmodify){ + contextMenu->addMenu(cNewMenu); + } + contextMenu->addMenu(cOpenMenu); } void DirWidget::currentDirectoryChanged(bool widgetonly){ @@ -528,10 +596,10 @@ void DirWidget::currentDirectoryChanged(bool widgetonly){ 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") ){ + if(!cur.contains("/.zfs/snapshot") ){ normalbasedir = cur; ui->group_snaps->setVisible(false); - emit findSnaps(ID, cur); + emit findSnaps(ID, cur); qDebug() << "Changed to directory:" << cur; }else{ //Re-assemble the normalbasedir variable (in case moving around within a snapshot) @@ -540,8 +608,11 @@ void DirWidget::currentDirectoryChanged(bool widgetonly){ qDebug() << "Changed to snapshot:" << cur << normalbasedir; } ui->actionBack->setEnabled( currentBrowser()->history().length()>1 ); - line_dir->setText(normalbasedir); + line_dir->setText(normalbasedir); emit TabNameChanged(ID, normalbasedir.section("/",-1)); + QModelIndex index = dirtreeModel->index(cur,0); + ui->folderViewPane->setCurrentIndex( index ); + ui->folderViewPane->scrollTo(index); } void DirWidget::dirStatusChanged(QString stat){ @@ -564,12 +635,12 @@ void DirWidget::setCurrentBrowser(QString id){ //Context Menu Functions void DirWidget::createNewFile(){ - if(!canmodify){ return; } //cannot create anything here + 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(!ok || newdocument.isEmpty()){ return; } //Create the empty file QString full = currentBrowser()->currentDirectory(); if(!full.endsWith("/")){ full.append("/"); } @@ -584,7 +655,7 @@ void DirWidget::createNewFile(){ //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.")); + QMessageBox::warning(this, tr("Error Creating Document"), tr("The document could not be created. Please ensure that you have the proper permissions.")); } } @@ -593,7 +664,7 @@ void DirWidget::createNewDir(){ //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); + &ok, 0, Qt::ImhFormattedNumbersOnly | Qt::ImhUppercaseOnly | Qt::ImhLowercaseOnly); if(!ok || newdir.isEmpty()){ return; } //Now create the new dir QString full = currentBrowser()->currentDirectory(); @@ -617,7 +688,7 @@ void DirWidget::createNewXDGEntry(){ 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(!ok || newdocument.isEmpty()){ return; } if(!newdocument.endsWith(".desktop")){ newdocument.append(".desktop"); } //Create the empty file QString full = currentBrowser()->currentDirectory(); @@ -633,57 +704,89 @@ void DirWidget::createNewXDGEntry(){ /*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); + emit CutFiles(sel); } void DirWidget::copyFiles(){ QStringList sel = currentBrowser()->currentSelection(); if(sel.isEmpty()){ return; } - emit CopyFiles(sel); + emit CopyFiles(sel); } void DirWidget::pasteFiles(){ if( !canmodify ){ return; } - emit PasteFiles(currentBrowser()->currentDirectory(), QStringList() ); + 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); + emit RenameFiles(sel); } void DirWidget::favoriteFiles(){ QStringList sel = currentBrowser()->currentSelection(); if(sel.isEmpty()){ return; } - emit FavoriteFiles(sel); + emit FavoriteFiles(sel); } void DirWidget::removeFiles(){ QStringList sel = currentBrowser()->currentSelection(); if(sel.isEmpty() || !canmodify){ return; } qDebug() << "Deleting selected Items:" << sel; - emit RemoveFiles(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++){ + 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 } @@ -696,13 +799,13 @@ void DirWidget::runWithFiles(){ QStringList sel = currentBrowser()->currentSelection(); if(sel.isEmpty()){ return; } QStringList dirs; - for(int i=0; i<sel.length(); i++){ + 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 } @@ -710,7 +813,7 @@ void DirWidget::runWithFiles(){ /*void DirWidget::attachToNewEmail(){ -}*/ +}*/ // - Context-specific operations void DirWidget::openInSlideshow(){ @@ -739,6 +842,18 @@ void DirWidget::openMultimedia(){ if(!list.isEmpty()){ emit PlayFiles(list); } } +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 //==================== diff --git a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.h b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.h index 5f06e2b6..20b677d7 100644 --- a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.h +++ b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.h @@ -15,6 +15,7 @@ #include <QLineEdit> #include <QShortcut> #include <QFileSystemWatcher> +#include <QFileSystemModel> #include <QTimer> #include <QFuture> @@ -33,28 +34,34 @@ 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 setFocusLineDir(); + void showDirTreePane(bool show); + bool showingDirTreePane(); + + + public slots: //void LoadDir(QString dir, LFileInfoList list); void LoadSnaps(QString basedir, QStringList snaps); - + //Refresh options void refresh(); //Refresh current directory @@ -69,18 +76,18 @@ private: 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; + bool canmodify, showdirtree; //The Toolbar and associated items QToolBar *toolbar; QLineEdit *line_dir; //The context menu and associated items - QMenu *contextMenu, *cNewMenu, *cOpenMenu, *cFModMenu, *cFViewMenu; + 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; + 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 @@ -89,19 +96,27 @@ private: 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 // -- Bottom Action Buttons void on_tool_zoom_in_clicked(); - void on_tool_zoom_out_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(); @@ -115,7 +130,7 @@ private slots: void fileCheckSums(); void fileProperties(); void openTerminal(); - + //Browser Functions void OpenContextMenu(); @@ -123,7 +138,8 @@ private slots: 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(); @@ -140,18 +156,20 @@ private slots: void removeFiles(); void runFiles(); void runWithFiles(); - //void attachToNewEmail(); + //void attachToNewEmail(); + void autoExtractFiles(); // - Context-specific operations void openInSlideshow(); - void openMultimedia(); + void openMultimedia(); + signals: //Directory loading/finding signals void OpenDirectories(QStringList); //Directories to open in other tabs/columns void findSnaps(QString, QString); //ID, dirpath (Request snapshot information for a directory) void CloseBrowser(QString); //ID (Request that this browser be closed) - + //External App/Widget launching void PlayFiles(LFileInfoList); //open in multimedia player void ViewFiles(LFileInfoList); //open in slideshow diff --git a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.ui b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.ui index 29660ad4..c49e99ac 100644 --- a/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.ui +++ b/src-qt5/desktop-utils/lumina-fm/widgets/DirWidget2.ui @@ -19,29 +19,11 @@ <property name="windowTitle"> <string>Form</string> </property> - <layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0" columnstretch="0,1"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <property name="horizontalSpacing"> - <number>1</number> - </property> - <property name="verticalSpacing"> - <number>2</number> - </property> - <item row="0" column="0" rowspan="2" colspan="2"> + <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,1,0"> + <item> <layout class="QHBoxLayout" name="toolbar_layout"/> </item> - <item row="2" column="1"> + <item> <layout class="QVBoxLayout" name="browser_layout_main"> <property name="spacing"> <number>1</number> @@ -122,12 +104,42 @@ </layout> </widget> </item> - <item> - <layout class="QHBoxLayout" name="browser_layout"/> - </item> </layout> </item> - <item row="3" column="0" colspan="2"> + <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"> diff --git a/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.cpp b/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.cpp index cf7a41cb..dfd859d7 100644 --- a/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.cpp +++ b/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.cpp @@ -98,6 +98,7 @@ void MainUI::setupPlayer(){ } void MainUI::setupPandora(){ + PANDORA = new PianoBarProcess(this); if(!LUtils::isValidBinary("pianobar")){ ui->radio_pandora->setEnabled(false); ui->radio_local->setChecked(true); @@ -107,7 +108,7 @@ void MainUI::setupPandora(){ } ui->radio_pandora->setToolTip(tr("Stream music from the Pandora online radio service")); ui->radio_pandora->setStatusTip(ui->radio_pandora->toolTip()); - PANDORA = new PianoBarProcess(this); + connect(PANDORA, SIGNAL(currentStateChanged(PianoBarProcess::State)), this, SLOT(PandoraStateChanged(PianoBarProcess::State)) ); connect(PANDORA, SIGNAL(NewInformation(QString)), this, SLOT(NewPandoraInfo(QString)) ); connect(PANDORA, SIGNAL(NowPlayingStation(QString, QString)), this, SLOT(PandoraStationChanged(QString)) ); diff --git a/src-qt5/desktop-utils/lumina-screenshot/MainUI.cpp b/src-qt5/desktop-utils/lumina-screenshot/MainUI.cpp index bdfbbfec..2bdd69ae 100644 --- a/src-qt5/desktop-utils/lumina-screenshot/MainUI.cpp +++ b/src-qt5/desktop-utils/lumina-screenshot/MainUI.cpp @@ -29,7 +29,7 @@ MainUI::MainUI() if(ui->spin_monitor->maximum()<2){ ui->spin_monitor->setEnabled(false); ui->radio_monitor->setEnabled(false); - } + } scaleTimer = new QTimer(this); scaleTimer->setSingleShot(true); scaleTimer->setInterval(200); //~1/5 second @@ -75,7 +75,7 @@ MainUI::MainUI() // Shortcuts quitShortcut = new QShortcut(Qt::CTRL + Qt::Key_Q, this); - connect(quitShortcut, SIGNAL(activated()), this, SLOT(on_quitShortcut_Triggered()) ); + connect(quitShortcut, SIGNAL(activated()), this, SLOT(quitShortcut_activated()) ); openShortcut = new QShortcut(Qt::CTRL + Qt::Key_O, this); connect(openShortcut, SIGNAL(activated()), this, SLOT(quicksave()) ); @@ -293,12 +293,12 @@ void MainUI::mouseReleaseEvent(QMouseEvent *ev){ QList<WId> wins = XCB->WindowList(); QList<WId> stack = XCB->WM_Get_Client_List(true); cwin = 0; - //qDebug() << "Try to select window:" << ev->globalPos(); + //qDebug() << "Try to select window:" << ev->globalPos(); for(int i=stack.length()-1; i>=0 && cwin==0; i--){ //work top->bottom in the stacking order if(!wins.contains(stack[i])){ continue; } - if( XCB->WindowGeometry(stack[i], true).contains(ev->globalPos()) && XCB->WindowState(stack[i])!=LXCB::INVISIBLE ){ + if( XCB->WindowGeometry(stack[i], true).contains(ev->globalPos()) && XCB->WindowState(stack[i])!=LXCB::INVISIBLE ){ //qDebug() << "Found Window:" << i << XCB->WindowClass(stack[i]); - cwin = stack[i]; + cwin = stack[i]; } } //qDebug() << " - Got window:" << cwin; @@ -338,6 +338,6 @@ void MainUI::closeEvent(QCloseEvent *ev){ QMainWindow::closeEvent(ev); } -void MainUI::on_quitShortcut_Triggered(){ +void MainUI::quitShortcut_activated(){ QApplication::quit(); } diff --git a/src-qt5/desktop-utils/lumina-screenshot/MainUI.h b/src-qt5/desktop-utils/lumina-screenshot/MainUI.h index 91d4966f..cd78dc3c 100644 --- a/src-qt5/desktop-utils/lumina-screenshot/MainUI.h +++ b/src-qt5/desktop-utils/lumina-screenshot/MainUI.h @@ -85,7 +85,7 @@ private slots: bool getWindow(); //set the "cwin" variable as appropriate void getPixmap(); //set the "cpic" variable to the new screenshot - void on_quitShortcut_Triggered(); + void quitShortcut_activated(); protected: void mousePressEvent(QMouseEvent *ev); diff --git a/src-qt5/desktop-utils/lumina-textedit/MainUI.cpp b/src-qt5/desktop-utils/lumina-textedit/MainUI.cpp index 145c7c7e..65979c46 100644 --- a/src-qt5/desktop-utils/lumina-textedit/MainUI.cpp +++ b/src-qt5/desktop-utils/lumina-textedit/MainUI.cpp @@ -18,6 +18,7 @@ #include <QTimer> #include <QMessageBox> #include <QActionGroup> +#include "PlainTextEditor.h" MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI){ ui->setupUi(this); @@ -118,7 +119,7 @@ MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI){ } MainUI::~MainUI(){ - + } void MainUI::LoadArguments(QStringList args){ //CLI arguments @@ -156,7 +157,7 @@ void MainUI::updateIcons(){ ui->tool_replace_all->setIcon(LXDG::findIcon("arrow-down-double")); ui->tool_hideReplaceGroup->setIcon(LXDG::findIcon("dialog-close","")); //ui->tool_find_next->setIcon(LXDG::findIcon("")); - + QTimer::singleShot(0,colorDLG, SLOT(updateIcons()) ); } @@ -255,6 +256,7 @@ void MainUI::changeFontSize(int newFontSize){ QFont currentFont = currentEditor()->document()->defaultFont(); currentFont.setPointSize(newFontSize); currentEditor()->document()->setDefaultFont(currentFont); + currentEditor()->updateLNW(); } void MainUI::changeTabsLocation(QAction *act){ @@ -301,10 +303,12 @@ void MainUI::showLineNumbers(bool show){ void MainUI::wrapLines(bool wrap){ settings->setValue("wrapLines",wrap); - for(int i=0; i<tabWidget->count(); i++){ + if(currentEditor() == 0){ return; } + currentEditor()->setLineWrapMode( wrap ? QPlainTextEdit::WidgetWidth : QPlainTextEdit::NoWrap); + /*for(int i=0; i<tabWidget->count(); i++){ PlainTextEditor *edit = static_cast<PlainTextEditor*>(tabWidget->widget(i)); edit->setLineWrapMode( wrap ? QPlainTextEdit::WidgetWidth : QPlainTextEdit::NoWrap); - } + }*/ } void MainUI::ModifyColors(){ @@ -351,6 +355,7 @@ void MainUI::tabChanged(){ //Update the font/size widgets to reflect what is set on this tab fontbox->setCurrentFont(font); fontSizes->setValue( font.pointSize() ); + ui->actionWrap_Lines->setChecked( cur->lineWrapMode()==QPlainTextEdit::WidgetWidth ); } void MainUI::tabClosed(int tab){ @@ -389,7 +394,7 @@ void MainUI::tabDraggedOut(int tab, Qt::DropAction act){ void MainUI::closeFindReplace(){ ui->groupReplace->setVisible(false); PlainTextEditor *cur = currentEditor(); - if(cur!=0){ cur->setFocus(); } + if(cur!=0){ cur->setFocus(); } } void MainUI::openFind(){ @@ -397,8 +402,8 @@ void MainUI::openFind(){ if(cur==0){ return; } ui->groupReplace->setVisible(true); ui->line_find->setText( cur->textCursor().selectedText() ); - ui->line_replace->setText(""); - ui->line_find->setFocus(); + ui->line_replace->setText(""); + ui->line_find->setFocus(); } void MainUI::openReplace(){ @@ -406,7 +411,7 @@ void MainUI::openReplace(){ if(cur==0){ return; } ui->groupReplace->setVisible(true); ui->line_find->setText( cur->textCursor().selectedText() ); - ui->line_replace->setText(""); + ui->line_replace->setText(""); ui->line_replace->setFocus(); } diff --git a/src-qt5/desktop-utils/lumina-textedit/PlainTextEditor.cpp b/src-qt5/desktop-utils/lumina-textedit/PlainTextEditor.cpp index a1b77732..653bd0e8 100644 --- a/src-qt5/desktop-utils/lumina-textedit/PlainTextEditor.cpp +++ b/src-qt5/desktop-utils/lumina-textedit/PlainTextEditor.cpp @@ -43,7 +43,7 @@ PlainTextEditor::PlainTextEditor(QSettings *set, QWidget *parent) : QPlainTextEd } PlainTextEditor::~PlainTextEditor(){ - + } void PlainTextEditor::showLineNumbers(bool show){ @@ -60,13 +60,14 @@ void PlainTextEditor::LoadSyntaxRule(QString type){ SYNTAX->loadRules(files[i]); break; } + if(i==files.length()-1){ SyntaxFile dummy; SYNTAX->loadRules(dummy); } } SYNTAX->rehighlight(); } void PlainTextEditor::updateSyntaxColors(){ SYNTAX->reloadRules(); - SYNTAX->rehighlight(); + SYNTAX->rehighlight(); } //File loading/setting options @@ -77,7 +78,7 @@ void PlainTextEditor::LoadFile(QString filepath){ this->clear(); QList<SyntaxFile> files = SyntaxFile::availableFiles(settings); for(int i=0; i<files.length(); i++){ - if(files[i].supportsFile(filepath) ){ + if(files[i].supportsFile(filepath) ){ files[i].SetupDocument(this); SYNTAX->loadRules(files[i]); break; @@ -125,7 +126,7 @@ QString PlainTextEditor::currentFile(){ } bool PlainTextEditor::hasChange(){ - return hasChanges; + return hasChanges; } //Functions for managing the line number widget @@ -134,11 +135,16 @@ int PlainTextEditor::LNWWidth(){ int lines = this->blockCount(); if(lines<1){ lines = 1; } int chars = 1; + //qDebug() << "point 1" << this->document()->defaultFont(); while(lines>=10){ chars++; lines/=10; } - return (this->fontMetrics().width("9")*chars); //make sure to add a tiny bit of padding + QFontMetrics metrics(this->document()->defaultFont()); + return (metrics.width("9")*chars); //make sure to add a tiny bit of padding } void PlainTextEditor::paintLNW(QPaintEvent *ev){ + //qDebug() << "Paint LNW Event:" << ev->rect() << LNW->geometry(); + //if(ev->rect().height() < (QFontMetrics(this->document()->defaultFont()).height() *1.5) ){ return; } + //qDebug() << " -- paint line numbers"; QPainter P(LNW); //First set the background color P.fillRect(ev->rect(), QColor("lightgrey")); @@ -146,19 +152,27 @@ void PlainTextEditor::paintLNW(QPaintEvent *ev){ QTextBlock block = this->firstVisibleBlock(); int bTop = blockBoundingGeometry(block).translated(contentOffset()).top(); int bBottom; +// QFont font = P.font(); +// font.setPointSize(this->document()->defaultFont().pointSize()); + P.setFont(this->document()->defaultFont()); //Now loop over the blocks (lines) and write in the numbers + QFontMetrics metrics(this->document()->defaultFont()); + //qDebug() << "point 2" << this->document()->defaultFont(); P.setPen(Qt::black); //setup the font color while(block.isValid() && bTop<=ev->rect().bottom()){ //ensure block below top of viewport bBottom = bTop+blockBoundingRect(block).height(); if(block.isVisible() && bBottom >= ev->rect().top()){ //ensure block above bottom of viewport - P.drawText(0,bTop, LNW->width(), this->fontMetrics().height(), Qt::AlignRight, QString::number(block.blockNumber()+1) ); + P.drawText(0,bTop, LNW->width(), metrics.height(), Qt::AlignRight, QString::number(block.blockNumber()+1) ); + //qDebug() << "bTop" << bTop; + //qDebug() << "LNW->width()" << LNW->width(); + //qDebug() << "metrics.height()" << metrics.height(); } //Go to the next block block = block.next(); bTop = bBottom; } } - + //============== // PRIVATE //============== @@ -177,7 +191,7 @@ void PlainTextEditor::clearMatchData(){ void PlainTextEditor::highlightMatch(QChar ch, bool forward, int fromPos, QChar startch){ if(forward){ matchleft = fromPos; } else{ matchright = fromPos; } - + int nested = 1; //always start within the first nest (the primary nest) int tmpFromPos = fromPos; //if(!forward){ tmpFromPos++; } //need to include the initial location @@ -192,7 +206,7 @@ void PlainTextEditor::highlightMatch(QChar ch, bool forward, int fromPos, QChar }else{ break; } }else{ QTextCursor cur = this->document()->find(ch, tmpFromPos, QTextDocument::FindBackward); - if(!cur.isNull()){ + if(!cur.isNull()){ QString mid = doc.mid(cur.position()-1, tmpFromPos-cur.position()+1); //qDebug() << "Found backwards match:" << nested << startch << ch << mid; //qDebug() << doc.mid(cur.position(),1) << doc.mid(tmpFromPos,1); @@ -202,10 +216,10 @@ void PlainTextEditor::highlightMatch(QChar ch, bool forward, int fromPos, QChar }else{ break; } } } - + //Now highlight the two characters - QList<QTextEdit::ExtraSelection> sels = this->extraSelections(); - if(matchleft>=0){ + QList<QTextEdit::ExtraSelection> sels = this->extraSelections(); + if(matchleft>=0){ QTextEdit::ExtraSelection sel; if(matchright>=0){ sel.format.setBackground( QColor(settings->value("colors/bracket-found").toString()) ); } else{ sel.format.setBackground( QColor(settings->value("colors/bracket-missing").toString()) ); } @@ -225,7 +239,7 @@ void PlainTextEditor::highlightMatch(QChar ch, bool forward, int fromPos, QChar if(!forward){ cur.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); } else{ cur.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); } sel.cursor = cur; - sels << sel; + sels << sel; } this->setExtraSelections(sels); } @@ -314,7 +328,7 @@ void PlainTextEditor::fileChanged(){ text.append("\n"); text.append( tr("(Note: You will lose all currently-unsaved changes)") ); text.append("\n\n%1"); - + if(!update){ update = (QMessageBox::Yes == QMessageBox::question(this, tr("File Modified"),text.arg(currentFile()) , QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ); } @@ -333,3 +347,7 @@ void PlainTextEditor::resizeEvent(QResizeEvent *ev){ QRect cGeom = this->contentsRect(); LNW->setGeometry( QRect(cGeom.left(), cGeom.top(), LNWWidth(), cGeom.height()) ); } + +void PlainTextEditor::updateLNW(){ + LNW_updateWidth(); +} diff --git a/src-qt5/desktop-utils/lumina-textedit/PlainTextEditor.h b/src-qt5/desktop-utils/lumina-textedit/PlainTextEditor.h index 64ff256b..0c83b7ce 100644 --- a/src-qt5/desktop-utils/lumina-textedit/PlainTextEditor.h +++ b/src-qt5/desktop-utils/lumina-textedit/PlainTextEditor.h @@ -37,6 +37,9 @@ public: //Functions for managing the line number widget (internal - do not need to run directly) int LNWWidth(); //replacing the LNW size hint detection void paintLNW(QPaintEvent *ev); //forwarded from the LNW paint event + void updateLNW(); + + QFontMetrics *metrics; private: QWidget *LNW; //Line Number Widget @@ -65,7 +68,7 @@ private slots: void textChanged(); void cursorMoved(); //Function for prompting the user if the file changed externally - void fileChanged(); + void fileChanged(); protected: void resizeEvent(QResizeEvent *ev); diff --git a/src-qt5/desktop-utils/lumina-textedit/syntax_rules/cpp.syntax b/src-qt5/desktop-utils/lumina-textedit/syntax_rules/cpp.syntax index 9a235ae3..f504263e 100644 --- a/src-qt5/desktop-utils/lumina-textedit/syntax_rules/cpp.syntax +++ b/src-qt5/desktop-utils/lumina-textedit/syntax_rules/cpp.syntax @@ -27,7 +27,7 @@ }, { "name": "keywords", - "words": ["char", "class", "const", "double", "enum", "explicit", "extern", "float", "friend", "inline", "int", "long", "namespace", "operator", "private", "protected", "public", "short", "signals", "signed", "slots", "static", "struct", "template", "typedef", "typename", "union", "unsigned", "virtual", "void", "volatile", "true", "false", "bool"], + "words": ["char", "class", "const", "double", "enum", "explicit", "extern", "float", "friend", "inline", "int", "long", "namespace", "operator", "private", "protected", "public", "short", "signals", "signed", "slots", "static", "struct", "template", "typedef", "typename", "union", "using","unsigned", "virtual", "void", "volatile", "true", "false", "bool"], "foreground": "colors/keyword", "font_weight": "bold" }, @@ -44,6 +44,11 @@ "font_weight": "bold" }, { + "name": "numbers", + "regex" : "\\b[0-9\\.]+\\b", + "foreground": "colors/text" + }, + { "name": "function names", "regex": "\\b[A-Za-z0-9_]+(?=\\()", "foreground": "colors/function" diff --git a/src-qt5/desktop-utils/lumina-textedit/syntax_rules/go.syntax b/src-qt5/desktop-utils/lumina-textedit/syntax_rules/go.syntax new file mode 100644 index 00000000..3eff96c1 --- /dev/null +++ b/src-qt5/desktop-utils/lumina-textedit/syntax_rules/go.syntax @@ -0,0 +1,49 @@ +# Syntax support file for the Lumina Text Editor +# =================================== +# Go language support rules +# Written by Zackary Welch <zwelch@ixsystems.com> +# Released under the 2-clause BSD license +# =================================== + +{ + "meta": { + "name": "Go", + "file_suffix": ["go"] + }, + "format": { + "line_wrap": false, + "highlight_whitespace_eol" : false + }, + "rules": [{ + "name": "keywords", + "words": ["break", "default", "func", "interface", "select", "case", "defer", "go", "map", "struct", "chan", "else", "goto", "package", "switch", "const", "fallthrough", "if", "range", "type", "continue", "for", "import", "return", "var", "uint32", "uint64", "float32", "float64"], + "foreground": "colors/keyword" + }, + { + "name": "single-line comment", + "regex": "//[^\n]*", + "foreground": "colors/comment" + }, + { + "name": "multi-line comment", + "regex_start": "/\\*", + "regex_end": "\\*/", + "foreground": "colors/comment" + }, + { + "name": "numbers", + "regex": "\\b[0-9]+\\.?[0-9]*\\b|[0-9]+e[\\+\\-]?[0-9]+", + "foreground": "colors/altkeyword" + }, + { + "name": "function names", + "regex": "\\b[A-Za-z0-9_]+(?=\\()", + "foreground": "colors/class" + }, + { + "name" : "text", + "regex": "\"[^\"\\\\]*(\\\\(.|\\n)[^\"\\\\]*)*\"|'[^'\\\\]*(\\\\(.|\\n)[^'\\\\]*)*'", + "foreground" : "colors/text" + } + ] +} diff --git a/src-qt5/desktop-utils/lumina-textedit/syntax_rules/html.syntax b/src-qt5/desktop-utils/lumina-textedit/syntax_rules/html.syntax new file mode 100644 index 00000000..22567a9b --- /dev/null +++ b/src-qt5/desktop-utils/lumina-textedit/syntax_rules/html.syntax @@ -0,0 +1,74 @@ +# Syntax support file for the Lumina Text Editor +# =================================== +# HTML language support rules +# Written by Ken Moore <ken@ixsystems.com> +# Released under the 2-clause BSD license +# =================================== + +{ + "meta": { + "name": "HTML", + "file_suffix": ["html", "htm"] + }, + "format": { + "line_wrap": false, + "highlight_whitespace_eol" : true, + "font_type" : "monospace", + "tab_width": 8 + }, + "rules": [{ + "name": "8 spaces rather than a tab", + "regex": "([ ]{8})+", + "background": "colors/bracket-missing" + }, + { + "name": "tabs after spaces", + "regex": "( )+\\t", + "background": "colors/bracket-missing" + }, + { + "name" : "odd number of spaces within indentation", + "regex": "(^|\\t)([ ]{2})*[ ](?=\\<)", + "background": "colors/bracket-missing" + }, + { + "name" : "ID of a tag", + "regex": "<[^> ]+[>]?", + "font_weight" : "bold", + "foreground" : "colors/function" + }, + { + "name" : "tag modifiers", + "regex" : "\\s[^\\= ]+(?=\\=)", + "foreground" : "colors/class" + }, + { + "name" : "strings inside a tag", + "regex": "\\\"[^\\\"]*\\\"", + "foreground" : "colors/text" + }, + { + "name" : "comment", + "regex_start" : "<!DOCTYPE", + "regex_end" : "[/]?>", + "foreground" : "colors/comment" + }, + { + "name" : "comment", + "regex_start" : "<!--", + "regex_end" : "-->", + "foreground" : "colors/comment" + }, + { + "name" : "escapes", + "regex" : "&[^;]*;", + "foreground" : "colors/preprocessor" + }, + { + "name" : "HTML preprocessor", + "regex_start" : "\\<\\?html ", + "regex_end" : "\\?>", + "foreground" : "colors/preprocessor" + } + ] +} diff --git a/src-qt5/desktop-utils/lumina-textedit/syntax_rules/javascript.syntax b/src-qt5/desktop-utils/lumina-textedit/syntax_rules/javascript.syntax new file mode 100644 index 00000000..02e1092a --- /dev/null +++ b/src-qt5/desktop-utils/lumina-textedit/syntax_rules/javascript.syntax @@ -0,0 +1,54 @@ +# Syntax support file for the Lumina Text Editor +# =================================== +# Javascript language support rules +# Written by Ken Moore <ken@ixsystems.com> +# Released under the 2-clause BSD license +# =================================== + +{ + "meta": { + "name": "Javascript", + "file_suffix": ["js"] + }, + "format": { + "line_wrap": false, + "highlight_whitespace_eol" : false + }, + "rules": [{ + "name": "keywords", + "words": ["export","function", "import", "from", "let", "if", "return", "for", "while"], + "foreground": "colors/keyword" + }, + { + "name": "single-line comment", + "regex": "//[^\n]*", + "foreground": "colors/comment" + }, + { + "name": "multi-line comment", + "regex_start": "/\\*", + "regex_end": "\\*/", + "foreground": "colors/comment" + }, + { + "name": "numbers", + "regex": "\\b[0-9]+\\.?[0-9]*\\b", + "foreground": "colors/altkeyword" + }, + { + "name": "attributes", + "regex": "(\\.)[A-Za-z_][A-Za-z0-9_]*(?![\\(a-zA-Z0-9])", + "foreground": "colors/function" + }, + { + "name": "function names", + "regex": "\\b[A-Za-z0-9_]+(?=\\()", + "foreground": "colors/class" + }, + { + "name" : "text", + "regex": "\"[^\"\\\\]*(\\\\(.|\\n)[^\"\\\\]*)*\"|'[^'\\\\]*(\\\\(.|\\n)[^'\\\\]*)*'", + "foreground" : "colors/text" + } + ] +} diff --git a/src-qt5/desktop-utils/lumina-textedit/syntax_rules/json.syntax b/src-qt5/desktop-utils/lumina-textedit/syntax_rules/json.syntax index fdca7211..ab67d384 100644 --- a/src-qt5/desktop-utils/lumina-textedit/syntax_rules/json.syntax +++ b/src-qt5/desktop-utils/lumina-textedit/syntax_rules/json.syntax @@ -8,7 +8,7 @@ { "meta": { "name": "JSON", - "file_suffix": ["json"] + "file_suffix": ["json", "syntax"] }, "format": { "line_wrap": false, diff --git a/src-qt5/desktop-utils/lumina-textedit/syntax_rules/md.syntax b/src-qt5/desktop-utils/lumina-textedit/syntax_rules/md.syntax new file mode 100644 index 00000000..2ba4bca7 --- /dev/null +++ b/src-qt5/desktop-utils/lumina-textedit/syntax_rules/md.syntax @@ -0,0 +1,103 @@ +# Syntax support file for the Lumina Text Editor +# =================================== +# Markdown language support rules +# Written by Zackary Welch <zwelch@ixsystems.com> +# Released under the 2-clause BSD license +# =================================== + +{ + "meta": { + "name": "Markdown", + "file_suffix": ["md", "markdown"] + }, + "format": { + "line_wrap": true, + "highlight_whitespace_eol" : false, + "tab_width" : 4 + }, + "rules": [{ + "name": "links", + "regex": "\\[[^\\[\\]]+\\]\\(#?[^\\s\\]\\)\\[\\(]*\\)", + "foreground": "colors/keyword" + }, + { + "name": "bold and italic", + "regex" : "[\\*]{3}(?!\\s)[^\\*\\_]+(?!\\s)[\\*]{3}", + "foreground": "colors/altkeyword", + "font_weight" : "bold", + "font_style" : "italic" + }, + { + "name": "bold", + "regex" : "[\\*]{2}(?!\\s)[^\\*\\_]+(?!\\s)[\\*]{2}", + "foreground": "colors/altkeyword", + "font_weight" : "bold" + }, + { + "name": "italic", + "regex" : "[\\*](?!\\s){1}[^\\*\\_]+(?!\\s)[\\*]{1}", + "foreground": "colors/altkeyword", + "font_style" : "italic" + }, + { + "name": "bold and italic", + "regex" : "[_]{3}(?!\\s)[^\\*\\_]+(?!\\s)[_]{3}", + "foreground": "colors/altkeyword", + "font_weight" : "bold", + "font_style" : "italic" + }, + { + "name": "bold", + "regex" : "[_]{2}(?!\\s)[^\\*\\_]+(?!\\s)[_]{2}", + "foreground": "colors/altkeyword", + "font_weight" : "bold" + }, + { + "name": "italic", + "regex" : "[_]{1}(?!\\s)[^\\*\\_]+(?!\\s)[_]{1}", + "foreground": "colors/altkeyword", + "font_style" : "italic" + }, + { + "name" : "markup", + "regex": "<[a-z].*><\\/[a-z]>", + "foreground" : "colors/class" + }, + { + "name" : "heading", + "regex": "^#+ (.)*$", + "foreground" : "colors/function" + }, + { + "name" : "horizontal rule", + "regex": "^((\\-\\s*\\-\\s*\\-\\s*)|(\\*\\s*\\*\\s*\\*)|(\\_\\s*\\_\\s*\\_\\s*))$", + "foreground" : "colors/function" + }, + { + "name" : "multi-line code block", + "regex_start" : "^```$", + "regex_end" : "^```$", + "foreground" : "colors/comment" + }, + { + "name" : "in-line code block", + "regex" : "`([^`])+`", + "foreground" : "colors/comment" + }, + { + "name" : "block quote", + "regex" : "^(\\> )+", + "foreground" : "colors/keyword" + }, + { + "name" : "lists", + "regex" : "^\\s*([0-9].|[\\*\\+\\-]{1})\\s+", + "foreground" : "colors/function" + }, + { + "name" : "text", + "regex": "\"[^\"\\\\]*(\\\\(.|\\n)[^\"\\\\]*)*\"|'[^'\\\\]*(\\\\(.|\\n)[^'\\\\]*)*'", + "foreground" : "colors/text" + } + ] +} diff --git a/src-qt5/desktop-utils/lumina-textedit/syntax_rules/php.syntax b/src-qt5/desktop-utils/lumina-textedit/syntax_rules/php.syntax new file mode 100644 index 00000000..15f6e2a5 --- /dev/null +++ b/src-qt5/desktop-utils/lumina-textedit/syntax_rules/php.syntax @@ -0,0 +1,49 @@ +# Syntax support file for the Lumina Text Editor +# =================================== +# PHP language support rules +# Written by Zackary Welch <zwelch@ixsystems.com> +# Released under the 2-clause BSD license +# =================================== + +{ + "meta": { + "name": "PHP", + "file_suffix": ["php"] + }, + "format": { + "line_wrap": false, + "highlight_whitespace_eol" : false + }, + "rules": [{ + "name": "keywords", + "words": ["private", "public", "class", "function", "const", "return", "if", "else", "bool", "abstract", "and", "as", "break", "case", "catch", "const", "do", "echo", "int", "elseif", "default", "endif", "endfor", "final", "for", "foreach", "extends", "global", "include", "interface", "new", "or", "protected", "require", "static", "switch", "throw", "try", "use", "var", "while", "xor"], + "foreground": "colors/keyword" + }, + { + "name": "single-line comment", + "regex": "[//#][^\n]*", + "foreground": "colors/comment" + }, + { + "name": "multi-line comment", + "regex_start": "/\\*", + "regex_end": "\\*/", + "foreground": "colors/comment" + }, + { + "name": "numbers", + "regex": "\\b[0-9]+\\.?[0-9]*\\b", + "foreground": "colors/altkeyword" + }, + { + "name": "function names", + "regex": "\\b[A-Za-z0-9_]+(?=\\()", + "foreground": "colors/class" + }, + { + "name" : "text", + "regex": "\"[^\"\\\\]*(\\\\(.|\\n)[^\"\\\\]*)*\"|'[^'\\\\]*(\\\\(.|\\n)[^'\\\\]*)*'", + "foreground" : "colors/text" + } + ] +} diff --git a/src-qt5/desktop-utils/lumina-textedit/syntax_rules/python.syntax b/src-qt5/desktop-utils/lumina-textedit/syntax_rules/python.syntax index f6d2223d..6690d98c 100644 --- a/src-qt5/desktop-utils/lumina-textedit/syntax_rules/python.syntax +++ b/src-qt5/desktop-utils/lumina-textedit/syntax_rules/python.syntax @@ -7,7 +7,7 @@ { "meta": { - "name": "Python (Experimental)", + "name": "Python", "file_suffix": ["py", "pyc"] }, "format": { @@ -37,6 +37,11 @@ "foreground": "colors/function" }, { + "name": "numbers", + "regex" : "\\b[0-9]+\\.?[0-9]*\\b", + "foreground": "colors/altkeyword" + }, + { "name": "text", "regex": "\"[^\"\\\\]*(\\\\(.|\\n)[^\"\\\\]*)*\"|'[^'\\\\]*(\\\\(.|\\n)[^'\\\\]*)*'", "foreground": "colors/text" diff --git a/src-qt5/desktop-utils/lumina-textedit/tests/test.go b/src-qt5/desktop-utils/lumina-textedit/tests/test.go new file mode 100644 index 00000000..0ae9b2dc --- /dev/null +++ b/src-qt5/desktop-utils/lumina-textedit/tests/test.go @@ -0,0 +1,185 @@ +// Source: https://github.com/golang/geo +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package r3 + +import ( + "fmt" + "math" + + "github.com/golang/geo/s1" +) + +// Vector represents a point in ℝ³. +type Vector struct { + X, Y, Z float64 +} + +// ApproxEqual reports whether v and ov are equal within a small epsilon. +func (v Vector) ApproxEqual(ov Vector) bool { + const epsilon = 1e-16 + return math.Abs(v.X-ov.X) < epsilon && math.Abs(v.Y-ov.Y) < epsilon && math.Abs(v.Z-ov.Z) < epsilon +} + +func (v Vector) String() string { return fmt.Sprintf("(%0.24f, %0.24f, %0.24f)", v.X, v.Y, v.Z) } + +// Norm returns the vector's norm. +func (v Vector) Norm() float64 { return math.Sqrt(v.Dot(v)) } + +// Norm2 returns the square of the norm. +func (v Vector) Norm2() float64 { return v.Dot(v) } + +// Normalize returns a unit vector in the same direction as v. +func (v Vector) Normalize() Vector { + if v == (Vector{0, 0, 0}) { + return v + } + return v.Mul(1 / v.Norm()) +} + +// IsUnit returns whether this vector is of approximately unit length. +func (v Vector) IsUnit() bool { + const epsilon = 5e-14 + return math.Abs(v.Norm2()-1) <= epsilon +} + +// Abs returns the vector with nonnegative components. +func (v Vector) Abs() Vector { return Vector{math.Abs(v.X), math.Abs(v.Y), math.Abs(v.Z)} } + +// Add returns the standard vector sum of v and ov. +func (v Vector) Add(ov Vector) Vector { return Vector{v.X + ov.X, v.Y + ov.Y, v.Z + ov.Z} } + +// Sub returns the standard vector difference of v and ov. +func (v Vector) Sub(ov Vector) Vector { return Vector{v.X - ov.X, v.Y - ov.Y, v.Z - ov.Z} } + +// Mul returns the standard scalar product of v and m. +func (v Vector) Mul(m float64) Vector { return Vector{m * v.X, m * v.Y, m * v.Z} } + +// Dot returns the standard dot product of v and ov. +func (v Vector) Dot(ov Vector) float64 { return v.X*ov.X + v.Y*ov.Y + v.Z*ov.Z } + +// Cross returns the standard cross product of v and ov. +func (v Vector) Cross(ov Vector) Vector { + return Vector{ + v.Y*ov.Z - v.Z*ov.Y, + v.Z*ov.X - v.X*ov.Z, + v.X*ov.Y - v.Y*ov.X, + } +} + +// Distance returns the Euclidean distance between v and ov. +func (v Vector) Distance(ov Vector) float64 { return v.Sub(ov).Norm() } + +// Angle returns the angle between v and ov. +func (v Vector) Angle(ov Vector) s1.Angle { + return s1.Angle(math.Atan2(v.Cross(ov).Norm(), v.Dot(ov))) * s1.Radian +} + +// Axis enumerates the 3 axes of ℝ³. +type Axis int + +// The three axes of ℝ³. +const ( + XAxis Axis = iota + YAxis + ZAxis +) + +// Ortho returns a unit vector that is orthogonal to v. +// Ortho(-v) = -Ortho(v) for all v. +func (v Vector) Ortho() Vector { + ov := Vector{0.012, 0.0053, 0.00457} + switch v.LargestComponent() { + case XAxis: + ov.Z = 1 + case YAxis: + ov.X = 1 + default: + ov.Y = 1 + } + return v.Cross(ov).Normalize() +} + +// LargestComponent returns the axis that represents the largest component in this vector. +func (v Vector) LargestComponent() Axis { + t := v.Abs() + + if t.X > t.Y { + if t.X > t.Z { + return XAxis + } + return ZAxis + } + if t.Y > t.Z { + return YAxis + } + return ZAxis +} + +// SmallestComponent returns the axis that represents the smallest component in this vector. +func (v Vector) SmallestComponent() Axis { + t := v.Abs() + + if t.X < t.Y { + if t.X < t.Z { + return XAxis + } + return ZAxis + } + if t.Y < t.Z { + return YAxis + } + return ZAxis +} + +// Cmp compares v and ov lexicographically and returns: +// +// -1 if v < ov +// 0 if v == ov +// +1 if v > ov +// +// This method is based on C++'s std::lexicographical_compare. Two entities +// are compared element by element with the given operator. The first mismatch +// defines which is less (or greater) than the other. If both have equivalent +// values they are lexicographically equal. +func (v Vector) Cmp(ov Vector) int { + if v.X < ov.X { + return -1 + } + if v.X > ov.X { + return 1 + } + + // First elements were the same, try the next. + if v.Y < ov.Y { + return -1 + } + if v.Y > ov.Y { + return 1 + } + + // Second elements were the same return the final compare. + if v.Z < ov.Z { + return -1 + } + if v.Z > ov.Z { + return 1 + } + + // Both are equal + return 0 +} diff --git a/src-qt5/desktop-utils/lumina-textedit/tests/test.html b/src-qt5/desktop-utils/lumina-textedit/tests/test.html new file mode 100644 index 00000000..a83618bc --- /dev/null +++ b/src-qt5/desktop-utils/lumina-textedit/tests/test.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> + +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + <title>Spoon-Knife</title> + <LINK href="styles.css" rel="stylesheet" type="text/css"> +</head> + +<body> + +<img src="forkit.gif" id="octocat" alt="" /> + +<!-- Feel free to change this text here --> +<p> + Fork me? Fork you, @octocat! +</p> + +</body> +</html> diff --git a/src-qt5/desktop-utils/lumina-textedit/tests/test.js b/src-qt5/desktop-utils/lumina-textedit/tests/test.js new file mode 100644 index 00000000..696cd74d --- /dev/null +++ b/src-qt5/desktop-utils/lumina-textedit/tests/test.js @@ -0,0 +1,44 @@ +import { distance } from "./math.js"; +import { polygonCentroid } from "d3-polygon"; + +export default function(start, end) { + let distances = start.map(p1 => end.map(p2 => squaredDistance(p1, p2))), + order = bestOrder(start, end, distances); + + // Don't permute huge array + if (start.length > 8) { + return start.map((d, i) => i); + } + return bestOrder(start, end, distances); +} + +export function bestOrder(start, end, distances) { + let min = Infinity, + best = start.map((d, i) => i); + + function permute(arr, order = [], sum = 0) { + for (let i = 0; i < arr.length; i++) { + let cur = arr.splice(i, 1), + dist = distances[cur[0]][order.length]; + if (sum + dist < min) { + if (arr.length) { + permute(arr.slice(), order.concat(cur), sum + dist); + } else { + min = sum + dist; + best = order.concat(cur); + } + } + if (arr.length) { + arr.splice(i, 0, cur[0]); + } + } + } + + permute(best); + return best; +} + +function squaredDistance(p1, p2) { + let d = distance(polygonCentroid(p1), polygonCentroid(p2)); + return d * d; +} diff --git a/src-qt5/desktop-utils/lumina-textedit/tests/test.md b/src-qt5/desktop-utils/lumina-textedit/tests/test.md new file mode 100644 index 00000000..fc6bc78b --- /dev/null +++ b/src-qt5/desktop-utils/lumina-textedit/tests/test.md @@ -0,0 +1,53 @@ + +# Header + +## Header 2 + +## Header 3 + +*Italic* + +**Bold** +***Bold and Italic*** +***a*** + +_Italic_ +__Bold__ +___Bold and Italic___ +___a___ +[link](link) + +Some [link](link) within a text block. + +Some [text](link) within a text block with another [Link](Link) in it. + +Horizontal Rules +--- +*** +___ +* * * +_ _ _ +* * * + +some `in-line code block` test in `a line`. + +some +``` +multi-line +code block +``` +outside block + +quote + +> > I like cheese > whine. +> Is what he said + +* Bullet List + * Indented bullet list + * indented 2 bullet list + +- or this bullet + +1. or this numbered list +2. second item diff --git a/src-qt5/desktop-utils/lumina-textedit/tests/test.php b/src-qt5/desktop-utils/lumina-textedit/tests/test.php new file mode 100644 index 00000000..d297c16b --- /dev/null +++ b/src-qt5/desktop-utils/lumina-textedit/tests/test.php @@ -0,0 +1,224 @@ +<?php + +class Mail +{ + private $from = ['name' => '', 'email' => '']; + private $to = []; + private $subject = ''; + private $message = ''; + private $files = []; + private $multipart = false; + private $boundary = ''; + private $uniqId = ''; + private $replyTo = []; + private $timestamp = null; + + const CRLF = "\r\n"; + + + public function __construct() + { + $this->uniqId = '<php-mail-' . md5(microtime()) . mt_rand() . '@git.php.net>'; + } + + /** + * Return unique id of mail + * @return string unique Id of message in format: '<php-mail-...@git.php.net'; + */ + public function getId() + { + return $this->uniqId; + } + + /** + * Add parent mail for this mail + * @param string $uniqId unique Id of message in format: '<php-mail-...@git.php.net'; + */ + public function addReplyTo($uniqId) + { + $this->replyTo[] = $uniqId; + } + + /** + * Add attached text file to mail + * @param string $name unique file name + * @param string $data file content + */ + public function addTextFile($name , $data) + { + $this->files[trim($name)] = chunk_split(base64_encode($data), 76, self::CRLF); + } + + /** + * Return length of attached file + * @param string $name unique file name + * @return int file length + */ + public function getFileLength($name) + { + $name = trim($name); + return isset($this->files[$name]) ? strlen($this->files[$name]) : 0; + } + + /** + * Delete attached file + * @param string $name unique file name + */ + public function dropFile($name) + { + $name = trim($name); + unset($this->files[$name]); + } + + /** + * Set "From" address + * @param string $email email author address + * @param string $name author name + */ + public function setFrom($email, $name = '') + { + $this->from = ['email' => trim($email), 'name' => trim($name)]; + } + + /** + * Add recipient address + * @param string $email recipient address + * @param string $name recipient name + */ + public function addTo($email, $name = '') + { + $this->to[] = ['email' => trim($email), 'name' => trim($name)]; + } + + /** + * Set mail subject + * @param string $subject subject + */ + public function setSubject($subject) + { + $this->subject = trim($subject); + } + + /** + * Set timestamp + * @param string $timestamp timestamp + */ + public function setTimestamp($timestamp) + { + $this->timestamp = trim($timestamp); + } + + /** + * Set mail body text + * @param string $message body text + */ + public function setMessage($message) + { + $this->message = $message; + } + + + /** + * Format header string + * @param string $name header name + * @param string $value header value + * @return string header string + */ + private function makeHeader($name, $value) + { + return $name . ': ' . $value; + } + + /** + * Format address string + * @param array $address array with email adress and name + * @return string address string + */ + private function makeAddress(array $address) + { + return $address['name'] ? $this->utf8SafeEncode($address['name'], 100) . ' <'. $address['email'] . '>' : $address['email']; + } + + /** + * Cut end encode string by mb_encode_mimeheader + * @param string $value utf8 string + * @param int $maxLenght max length + * @return string encoded string + */ + private function utf8SafeEncode($value, $maxLenght = null) + { + if ($maxLenght) $value = mb_substr($value, 0, $maxLenght); + return mb_encode_mimeheader($value, 'UTF-8', 'Q'); + } + + /** + * Prepare heade part of mail + * @return string header part of mail + */ + private function makeHeaders() + { + $headers = []; + $headers[] = $this->makeHeader('From', $this->makeAddress($this->from)); + $headers[] = $this->makeHeader('Message-ID', $this->uniqId); + if (count($this->replyTo)) { + $replyTo = implode(' ', $this->replyTo); + $headers[] = $this->makeHeader('References', $replyTo); + $headers[] = $this->makeHeader('In-Reply-To', $replyTo); + } + $headers[] = $this->makeHeader('MIME-Version', '1.0'); + $headers[] = $this->makeHeader('Date', date(DATE_RFC2822, $this->timestamp ?: time())); + if ($this->multipart) { + $this->boundary = sha1($this->uniqId); + $headers[] = $this->makeHeader('Content-Type', 'multipart/mixed; boundary="' . $this->boundary . '"'); + } else { + $headers[] = $this->makeHeader('Content-Type', 'text/plain; charset="utf-8"'); + // we use base64 for avoiding some problems sush string length limit, safety encoding etc. + $headers[] = $this->makeHeader('Content-Transfer-Encoding', 'quoted-printable'); + } + return implode(self::CRLF , $headers); + } + + /** + * Prepare body part of mail + * @return string mail body + */ + private function makeBody() + { + $body = ''; + if ($this->multipart) { + $body .= '--' . $this->boundary . self::CRLF; + $body .= $this->makeHeader('Content-Type', 'text/plain; charset="utf-8"') . self::CRLF; + $body .= $this->makeHeader('Content-Transfer-Encoding', 'quoted-printable') . self::CRLF; + $body .= self::CRLF; + $body .= quoted_printable_encode($this->message); + foreach ($this->files as $name => $data) { + $body .= self::CRLF . '--' . $this->boundary . self::CRLF; + $body .= $this->makeHeader('Content-Type', 'text/plain; charset="utf-8"') . self::CRLF; + $body .= $this->makeHeader('Content-Transfer-Encoding', 'base64') . self::CRLF; + $body .= $this->makeHeader('Content-Disposition', 'attachment; filename="' . $name . '"') . self::CRLF; + $body .= self::CRLF; + $body .= $data; + } + $body .= self::CRLF . '--' . $this->boundary . '--'; + } else { + $body = quoted_printable_encode($this->message); + } + return $body; + } + + /** + * Send current mail + * @return bool + */ + public function send() + { + $this->multipart = (bool) count($this->files); + + $receivers = implode(', ', array_map([$this, 'makeAddress'], $this->to)); + $subject = $this->utf8SafeEncode($this->subject, 450); + $headers = $this->makeHeaders(); + $body = $this->makeBody(); + + return mail($receivers, $subject, $body, $headers, "-f noreply@php.net"); + } +} diff --git a/src-qt5/desktop-utils/lumina-textedit/tests/test.py b/src-qt5/desktop-utils/lumina-textedit/tests/test.py new file mode 100644 index 00000000..cfac4984 --- /dev/null +++ b/src-qt5/desktop-utils/lumina-textedit/tests/test.py @@ -0,0 +1,17 @@ +import math + +primes = [2] +print(2, end=' ') +count = 1; +for i in range(3, 200000): + for j in primes: + if i % j == 0: + break + elif j > math.sqrt(i): + count += 1 + print(i, end=' ') + if count % 5 == 0: + print() + primes.append(i) + break +print() |