diff options
author | Ken Moore <ken@ixsystems.com> | 2017-06-22 04:55:42 -0400 |
---|---|---|
committer | Ken Moore <ken@ixsystems.com> | 2017-06-22 04:55:42 -0400 |
commit | 60b24de5be126f387e5bd4ea654c36e7f0bdd0d4 (patch) | |
tree | 9e9bd4b7865f46b0deae7619be296c8994fb8660 | |
parent | Oops - forgot to add the new test.xml file to the last commit. (diff) | |
parent | Start a large update to LuminaRandR info retrieval routine. (diff) | |
download | lumina-60b24de5be126f387e5bd4ea654c36e7f0bdd0d4.tar.gz lumina-60b24de5be126f387e5bd4ea654c36e7f0bdd0d4.tar.bz2 lumina-60b24de5be126f387e5bd4ea654c36e7f0bdd0d4.zip |
Merge branch 'master' of github.com:trueos/lumina
54 files changed, 1668 insertions, 469 deletions
diff --git a/icon-theme/material-design-dark/actions/formula.svg b/icon-theme/material-design-dark/actions/formula.svg new file mode 100644 index 00000000..00aced0e --- /dev/null +++ b/icon-theme/material-design-dark/actions/formula.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full" width="24" height="24" viewBox="0 0 24.00 24.00" enable-background="new 0 0 24.00 24.00" xml:space="preserve"> + <path fill="#F8F8F8" fill-opacity="1" stroke-width="1.33333" stroke-linejoin="round" d="M 15.5987,5.28811C 14.4983,5.19184 13.5282,6.00582 13.432,7.10618L 13.1788,10L 16,10L 16,12L 13.0038,12L 12.5604,17.0681C 12.3679,19.2689 10.4278,20.8968 8.22702,20.7043C 6.9208,20.59 5.81636,19.8601 5.1746,18.8254L 6.67042,17.3296C 6.90899,18.0735 7.57426,18.6395 8.40133,18.7119C 9.50169,18.8082 10.4718,17.9942 10.568,16.8938L 10.9962,12L 8,12L 8,10L 11.1712,10L 11.4396,6.93188C 11.6321,4.73115 13.5722,3.10319 15.773,3.29573C 17.0792,3.41001 18.1836,4.13994 18.8254,5.1746L 17.3296,6.67041C 17.091,5.92647 16.4257,5.36046 15.5987,5.28811 Z "/> +</svg> diff --git a/icon-theme/material-design-light/actions/formula.svg b/icon-theme/material-design-light/actions/formula.svg new file mode 100644 index 00000000..6c84a06e --- /dev/null +++ b/icon-theme/material-design-light/actions/formula.svg @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full" width="24" height="24" viewBox="0 0 24.00 24.00" enable-background="new 0 0 24.00 24.00" xml:space="preserve"> + <path fill="#000000" fill-opacity="1" stroke-width="1.33333" stroke-linejoin="round" d="M 15.5987,5.28811C 14.4983,5.19184 13.5282,6.00582 13.432,7.10618L 13.1788,10L 16,10L 16,12L 13.0038,12L 12.5604,17.0681C 12.3679,19.2689 10.4278,20.8968 8.22702,20.7043C 6.9208,20.59 5.81636,19.8601 5.1746,18.8254L 6.67042,17.3296C 6.90899,18.0735 7.57426,18.6395 8.40133,18.7119C 9.50169,18.8082 10.4718,17.9942 10.568,16.8938L 10.9962,12L 8,12L 8,10L 11.1712,10L 11.4396,6.93188C 11.6321,4.73115 13.5722,3.10319 15.773,3.29573C 17.0792,3.41001 18.1836,4.13994 18.8254,5.1746L 17.3296,6.67041C 17.091,5.92647 16.4257,5.36046 15.5987,5.28811 Z "/> +</svg> diff --git a/port-files/FreeBSD/deskutils/lumina-textedit/pkg-plist b/port-files/FreeBSD/deskutils/lumina-textedit/pkg-plist index cfe8ed17..bf8a3b04 100644 --- a/port-files/FreeBSD/deskutils/lumina-textedit/pkg-plist +++ b/port-files/FreeBSD/deskutils/lumina-textedit/pkg-plist @@ -64,7 +64,11 @@ share/lumina-desktop/i18n/l-te_zh_HK.qm share/lumina-desktop/i18n/l-te_zh_TW.qm share/lumina-desktop/i18n/l-te_zu.qm share/lumina-desktop/syntax_rules/cpp.syntax +share/lumina-desktop/syntax_rules/html.syntax +share/lumina-desktop/syntax_rules/javascript.syntax share/lumina-desktop/syntax_rules/json.syntax +share/lumina-desktop/syntax_rules/md.syntax +share/lumina-desktop/syntax_rules/php.syntax share/lumina-desktop/syntax_rules/python.syntax share/lumina-desktop/syntax_rules/README.md share/lumina-desktop/syntax_rules/rst.syntax diff --git a/port-files/FreeBSD/x11/lumina-core/pkg-plist b/port-files/FreeBSD/x11/lumina-core/pkg-plist index 4fdb6264..358c3182 100644 --- a/port-files/FreeBSD/x11/lumina-core/pkg-plist +++ b/port-files/FreeBSD/x11/lumina-core/pkg-plist @@ -215,6 +215,7 @@ share/icons/material-design-dark/scalable/actions/format-view-headline.svg share/icons/material-design-dark/scalable/actions/format-view-list.svg share/icons/material-design-dark/scalable/actions/format-view-tiles.svg share/icons/material-design-dark/scalable/actions/format-view-week.svg +share/icons/material-design-dark/scalable/actions/formula.svg share/icons/material-design-dark/scalable/actions/go-bottom.svg share/icons/material-design-dark/scalable/actions/go-down-search.svg share/icons/material-design-dark/scalable/actions/go-down.svg @@ -1027,6 +1028,7 @@ share/icons/material-design-light/scalable/actions/format-view-headline.svg share/icons/material-design-light/scalable/actions/format-view-list.svg share/icons/material-design-light/scalable/actions/format-view-tiles.svg share/icons/material-design-light/scalable/actions/format-view-week.svg +share/icons/material-design-light/scalable/actions/formula.svg share/icons/material-design-light/scalable/actions/go-bottom.svg share/icons/material-design-light/scalable/actions/go-down-search.svg share/icons/material-design-light/scalable/actions/go-down.svg diff --git a/src-qt5/core-utils/lumina-xconfig/MainUI.cpp b/src-qt5/core-utils/lumina-xconfig/MainUI.cpp index 169302ca..6553bb37 100644 --- a/src-qt5/core-utils/lumina-xconfig/MainUI.cpp +++ b/src-qt5/core-utils/lumina-xconfig/MainUI.cpp @@ -32,7 +32,7 @@ MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI){ } MainUI::~MainUI(){ - + } void MainUI::loadIcons(){ @@ -55,10 +55,10 @@ QStringList MainUI::currentOpts(){ if(SCREENS[i].order <0){ continue; } //skip this screen - non-active opts << "--output" << SCREENS[i].ID << "--mode" << QString::number(SCREENS[i].geom.width())+"x"+QString::number(SCREENS[i].geom.height()); if(SCREENS[i].isprimary){ opts << "--primary"; } - if(SCREENS[i].order > 0){ + if(SCREENS[i].order > 0){ //Get the ID of the previous screen - QString id; - for(int j=0; j<SCREENS.length(); j++){ + QString id; + for(int j=0; j<SCREENS.length(); j++){ if(SCREENS[j].order == SCREENS[i].order-1){ id = SCREENS[j].ID; break;} } if(!id.isEmpty()){ opts << "--right-of" << id; } @@ -78,6 +78,14 @@ ScreenInfo MainUI::currentScreenInfo(){ return ScreenInfo(); } +void MainUI::AddScreenToWidget(ScreenInfo screen){ + QListWidgetItem *it = new QListWidgetItem(); + it->setTextAlignment(Qt::AlignCenter); + it->setText( screen.ID+"\n\n ("+QString::number(screen.geom.x())+", "+QString::number(screen.geom.y())+")\n ("+QString::number(screen.geom.width())+"x"+QString::number(screen.geom.height())+") " ); + it->setWhatsThis(screen.ID); + ui->list_screens->addItem(it); +} + void MainUI::UpdateScreens(){ //First probe the server for current screens SCREENS = RRSettings::CurrentScreens(); @@ -86,10 +94,10 @@ void MainUI::UpdateScreens(){ for(int i=0; i<info.length(); i++){ if(info[i].contains("connected") ){ //qDebug() << "xrandr info:" << info[i]; - if(!cscreen.ID.isEmpty()){ + if(!cscreen.ID.isEmpty()){ SCREENS << cscreen; //current screen finished - save it into the array - cscreen = ScreenInfo(); //Now create a new structure - } + cscreen = ScreenInfo(); //Now create a new structure + } //qDebug() << "Line:" << info[i]; QString dev = info[i].section(" ",0,0); //device ID //The device resolution can be either the 3rd or 4th output - check both @@ -112,7 +120,7 @@ void MainUI::UpdateScreens(){ cscreen.ID = dev; //Note: devres format: "<width>x<height>+<xoffset>+<yoffset>" cscreen.geom.setRect( devres.section("+",-2,-2).toInt(), devres.section("+",-1,-1).toInt(), devres.section("x",0,0).toInt(), devres.section("+",0,0).section("x",1,1).toInt() ); - + }else if(info[i].contains(" connected")){ //Device that is connected, but not attached qDebug() << "Create new Screen entry:" << dev << "none"; @@ -136,22 +144,31 @@ void MainUI::UpdateScreens(){ while(found){ found = false; //make sure to break out if a screen is not found for(int i=0; i<SCREENS.length(); i++){ - if(SCREENS[i].order != -1){} //already evaluated - skip it + if(SCREENS[i].order != -1){qDebug() << "Skip Screen:" << i << SCREENS[i].order; } //already evaluated - skip it else if(SCREENS[i].geom.x()==xoffset){ found = true; //make sure to look for the next one xoffset = xoffset+SCREENS[i].geom.width(); //next number to look for SCREENS[i].order = cnum; //assign the current order to it cnum++; //get ready for the next one - QListWidgetItem *it = new QListWidgetItem(); + AddScreenToWidget(SCREENS[i]); + /*QListWidgetItem *it = new QListWidgetItem(); it->setTextAlignment(Qt::AlignCenter); - it->setText( SCREENS[i].ID+"\n ("+QString::number(SCREENS[i].geom.width())+"x"+QString::number(SCREENS[i].geom.height())+") " ); + it->setText( SCREENS[i].ID+"\n ("+QString::number(SCREENS[i].geom.x())+", "+QString::number(SCREENS[i].geom.y())+")\n("+QString::number(SCREENS[i].geom.width())+"x"+QString::number(SCREENS[i].geom.height())+") " ); it->setWhatsThis(SCREENS[i].ID); - ui->list_screens->addItem(it); - if(SCREENS[i].ID==csel){ ui->list_screens->setCurrentItem(it); } + ui->list_screens->addItem(it);*/ + //if(SCREENS[i].ID==csel){ ui->list_screens->setCurrentItem(it); } + }else if(SCREENS[i].geom.x() < xoffset || SCREENS[i].geom.x() > xoffset){ + //Screen not aligned with previous screen edge + qDebug() << "Found mis-aligned screen:" << i << SCREENS[i].ID; + found = true; //make sure to look for the next one + xoffset = xoffset+SCREENS[i].geom.width(); //next number to look for + SCREENS[i].order = cnum; //assign the current order to it + cnum++; //get ready for the next one + AddScreenToWidget(SCREENS[i]); } } } - + //Now update the available/current screens in the UI ui->combo_availscreens->clear(); ui->combo_cscreens->clear(); @@ -219,7 +236,7 @@ void MainUI::MoveScreenLeft(){ } //Now run the command QStringList opts = currentOpts(); - LUtils::runCmd("xrandr", opts); + LUtils::runCmd("xrandr", opts); //Now run the command //LUtils::runCmd("xrandr", QStringList() << "--output" << CID << "--left-of" << LID); QTimer::singleShot(500, this, SLOT(UpdateScreens()) ); diff --git a/src-qt5/core-utils/lumina-xconfig/MainUI.h b/src-qt5/core-utils/lumina-xconfig/MainUI.h index b8be8701..5a1a62cc 100644 --- a/src-qt5/core-utils/lumina-xconfig/MainUI.h +++ b/src-qt5/core-utils/lumina-xconfig/MainUI.h @@ -38,6 +38,8 @@ private: QStringList currentOpts(); + void AddScreenToWidget(ScreenInfo); + private slots: void UpdateScreens(); void ScreenSelected(); diff --git a/src-qt5/core/libLumina/ExternalProcess.h b/src-qt5/core/libLumina/ExternalProcess.h index 8329c361..a8a5e605 100644 --- a/src-qt5/core/libLumina/ExternalProcess.h +++ b/src-qt5/core/libLumina/ExternalProcess.h @@ -23,26 +23,26 @@ private: private slots: void resetCursor(){ - if(!cursorRestored){ - QApplication::restoreOverrideCursor(); - cursorRestored = true; + if(!cursorRestored){ + QApplication::restoreOverrideCursor(); + cursorRestored = true; } } void processStarting(){ - if(!cursorRestored){ + if(!cursorRestored){ QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); QTimer::singleShot(15000, this, SLOT(resetCursor()) ); } } void processFinished(){ - if(!cursorRestored){ - QApplication::restoreOverrideCursor(); + if(!cursorRestored){ + QApplication::restoreOverrideCursor(); cursorRestored = true; } //Clean up this object this->deleteLater(); } - + public: ExternalProcess(QString logfile = "", bool manageCursors = true) : QProcess(){ this->setProcessChannelMode(QProcess::MergedChannels); diff --git a/src-qt5/core/libLumina/LIconCache.h b/src-qt5/core/libLumina/LIconCache.h index 9834b2a3..0344e0f3 100644 --- a/src-qt5/core/libLumina/LIconCache.h +++ b/src-qt5/core/libLumina/LIconCache.h @@ -45,7 +45,7 @@ public: bool exists(QString icon); bool isLoaded(QString icon); QString findFile(QString icon); //find the full path of a given file/name (searching the current Icon theme) - + //Special loading routines for QLabel and QAbstractButton (pushbutton, toolbutton, etc) void loadIcon(QAbstractButton *button, QString icon, bool noThumb = false); void loadIcon(QLabel *label, QString icon, bool noThumb = false); diff --git a/src-qt5/core/libLumina/LuminaRandR-X11.cpp b/src-qt5/core/libLumina/LuminaRandR-X11.cpp index f8907741..0e68cfd2 100644 --- a/src-qt5/core/libLumina/LuminaRandR-X11.cpp +++ b/src-qt5/core/libLumina/LuminaRandR-X11.cpp @@ -6,11 +6,7 @@ //=========================================== #include "LuminaRandR.h" -//#include "xcb/randr.h" -//#include "xcb/xcb_atom.h" - -#include <QDebug> -#include <QX11Info> +//#include "X11/extensions/Xrandr.h" inline QString atomToName(xcb_atom_t atom){ xcb_get_atom_name_reply_t *nreply = xcb_get_atom_name_reply(QX11Info::connection(), xcb_get_atom_name_unchecked(QX11Info::connection(), atom), NULL); @@ -27,7 +23,7 @@ inline QStringList atomsToNames(xcb_atom_t *atoms, unsigned int num){ for(unsigned int i=0; i<num; i++){ cookies << xcb_get_atom_name_unchecked(QX11Info::connection(), atoms[i]); } QStringList names; //qDebug() << " - Get names"; - for(int i=0; i<cookies.length(); i++){ + for(int i=0; i<cookies.length(); i++){ xcb_get_atom_name_reply_t *nreply = xcb_get_atom_name_reply(QX11Info::connection(), cookies[i], NULL); if(nreply==0){ continue; } names << QString::fromLocal8Bit(xcb_get_atom_name_name(nreply), xcb_get_atom_name_name_length(nreply)); @@ -36,6 +32,52 @@ inline QStringList atomsToNames(xcb_atom_t *atoms, unsigned int num){ return names; }; +inline bool loadScreenInfo(p_objects *p_obj, xcb_randr_monitor_info_t *info){ + if(p_obj->monitor_atom == 0){ p_obj->monitor_atom = info->name; } + if(p_obj->name.isEmpty()){ p_obj->name = atomToName(info->name); } + //Now update all the info in the cache + p_obj->primary = (info->primary == 1); + p_obj->automatic = (info->automatic == 1); + p_obj->geometry = QRect(info->x, info->y, info->width, info->height); + p_obj->physicalSizeMM = QSize(info->width_in_millimeters, info->height_in_millimeters); + //Load the "outputs" + /*p_obj->outputs.clear(); + int out_len = xcb_randr_monitor_info_outputs_length(info); + for(int i=0; i<out_len; i++){ p_obj->outputs << xcb_randr_monitor_info_outputs(info)[i]; } + qDebug() << "Info Loaded:" << p_obj->name; + for(int i=0; i<p_obj->outputs.length(); i++){*/ + xcb_randr_get_output_info_reply_t *info = xcb_randr_get_output_info_reply(QX11Info::connection(), + xcb_randr_get_output_info_unchecked(QX11Info::connection(), p_obj->output, QX11Info::appTime()), + NULL); + if(info==0){ continue; } //bad output + //Modes + int mode_len = xcb_randr_get_output_info_modes_length(info); + //qDebug() << "Number of Modes:" << mode_len; + if(mode_len<=0){ continue; } //skip this output - not a physical screen which can be used + p_obj->modes.clear(); + for(int j=0; j<mode_len; j++){ + p_obj->modes.append( xcb_randr_get_output_info_modes(info)[j] ); + } + //} + //qDebug() << "INFO:" << p_obj->name; + //qDebug() << "Found Outputs:" << p_obj->outputs; + //qDebug() << "Found Modes:" << p_obj->modes; + p_obj->resolutions.clear(); + xcb_randr_get_screen_resources_reply_t *srreply = xcb_randr_get_screen_resources_reply(QX11Info::connection(), + xcb_randr_get_screen_resources_unchecked(QX11Info::connection(), QX11Info::appRootWindow()), NULL); + if(srreply!=0){ + for(int i=0; i<xcb_randr_get_screen_resources_modes_length(srreply); i++){ + xcb_randr_mode_info_t minfo = xcb_randr_get_screen_resources_modes(srreply)[i]; + if(p_obj->modes.contains(minfo.id)){ + QSize sz(minfo.width, minfo.height); + if(!p_obj->resolutions.contains(sz)){ p_obj->resolutions.append( sz); } + } + } + free(srreply); + } + return true; +} + /*class OutputDevice::p_objects{ public: xcb_atom_t monitor_atom; //This is the index used to identify particular monitors (unique ID) @@ -53,7 +95,7 @@ public: primary = automatic = false; monitor_atom = 0; } - + };*/ //Global Listing of Devices @@ -62,7 +104,7 @@ QList<OutputDevice> OutputDevice::availableMonitors(){ //Get the list of monitors xcb_randr_get_monitors_cookie_t cookie = xcb_randr_get_monitors_unchecked(QX11Info::connection(), QX11Info::appRootWindow(), 1); xcb_randr_get_monitors_reply_t *reply = xcb_randr_get_monitors_reply(QX11Info::connection(), cookie, NULL); - if(reply==0){ + if(reply==0){ qDebug() << "Could not get monitor list"; return list; } @@ -98,6 +140,13 @@ OutputDevice::OutputDevice(QString id){ p_obj.name = id; p_obj.primary = p_obj.automatic = false; p_obj.monitor_atom = 0; + p_obj.output = 0; + bool ok = false; + p_obj.output = id.toInt(&ok); + if(ok){ + //output ID number instead + p_obj.name.clear(); + } updateInfoCache(); } @@ -106,13 +155,16 @@ OutputDevice::~OutputDevice(){ } // INFORMATION FUNCTIONS (simply read from cache) -QString OutputDevice::ID(){ qDebug() << "Find ID"; return p_obj.name; } -bool OutputDevice::isEnabled(){ return p_obj.monitor_atom !=0; } +QString OutputDevice::ID(){ return p_obj.name; } +bool OutputDevice::isEnabled(){ return !p_obj.geometry.isNull(); } bool OutputDevice::isPrimary(){ return p_obj.primary; } bool OutputDevice::isAutomatic(){ return p_obj.automatic; } +bool OutputDevice::isConnected(){ return !p_obj.modes.isEmpty(); } + QList<QSize> OutputDevice::availableResolutions(){ return p_obj.resolutions; } QSize OutputDevice::currentResolution(){ return p_obj.geometry.size(); } //no concept of panning/scaling yet QRect OutputDevice::currentGeometry(){ return p_obj.geometry; } +QSize OutputDevice::physicalSizeMM(){ return p_obj.physicalSizeMM; } //Modification bool OutputDevice::setAsPrimary(bool set){ @@ -128,10 +180,22 @@ bool OutputDevice::setAsPrimary(bool set){ } bool OutputDevice::disable(){ + //qDebug() << "Disable Monitor:" << p_obj.monitor_atom; if(p_obj.monitor_atom!=0){ - xcb_randr_delete_monitor(QX11Info::connection(), QX11Info::appRootWindow(), p_obj.monitor_atom); - p_obj.monitor_atom = 0; - return true; + //qDebug() << " - Go ahead"; + for(int o=0; o<p_obj.outputs.length(); o++){ + for(int m=0; m<p_obj.modes.length(); m++){ + qDebug() << "Deleting Mode for Output:" << "Mode:" << p_obj.modes[m] << "Output:" << p_obj.outputs[o]; + //XLib version + //XRRDeleteOutputMode(QX11Info::display(), p_obj.outputs[o], p_obj.modes[m]); + //XCB version + xcb_randr_delete_output_mode(QX11Info::connection(), p_obj.outputs[o], p_obj.modes[m]); + xcb_flush(QX11Info::connection()); + } + } + //xcb_randr_delete_monitor_checked(QX11Info::connection(), QX11Info::appRootWindow(), p_obj.monitor_atom); + //p_obj.monitor_atom = 0; + return true; } return false; } @@ -148,53 +212,43 @@ void OutputDevice::changeResolution(QSize){ } void OutputDevice::updateInfoCache(){ + xcb_randr_get_screen_resources_reply_t *reply = xcb_randr_get_screen_resources_reply(QX11Info::connection(), + xcb_randr_get_screen_resources_unchecked(QX11Info::connection(), QX11Info::appRootWindow()), + NULL); + int outputnum = xcb_randr_get_screen_resources_outputs_length(reply); + for(int i=0; i<outputnum; i++){ + xcb_randr_output_t output = xcb_randr_get_screen_resources_outputs(reply)[i]; + if(p_obj->output==0){ + //Need to detect the name for this output (inefficient - better to pass in the output number directly) + xcb_randr_get_output_info_reply_t *info = xcb_randr_get_output_info_reply(QX11Info::connection(), + xcb_randr_get_output_info_unchecked(QX11Info::connection(), output, QX11Info::appTime()), + NULL); + //Name + QString name = QString::fromLocal8Bit( (char*) xcb_randr_get_output_info_name(info), xcb_randr_get_output_info_name_length(info)); + if( + } + //Find the **active** monitor with the given id/name if(p_obj.monitor_atom !=0 || !p_obj.name.isEmpty() ){ - xcb_randr_get_monitors_cookie_t cookie = xcb_randr_get_monitors_unchecked(QX11Info::connection(), QX11Info::appRootWindow(), 1); - xcb_randr_get_monitors_reply_t *reply = xcb_randr_get_monitors_reply(QX11Info::connection(), cookie, NULL); - if(reply!=0){ - xcb_randr_monitor_info_iterator_t iter = xcb_randr_get_monitors_monitors_iterator(reply); - //qDebug() << "Number of Monitors:" << xcb_randr_get_monitors_monitors_length(reply); - while(iter.rem>0){ - //qDebug() << " Index:" << iter.index << "Rem:" << iter.rem; - if( p_obj.monitor_atom == iter.data->name || p_obj.name == atomToName(iter.data->name) ){ - if(p_obj.monitor_atom == 0){ p_obj.monitor_atom = iter.data->name; } - if(p_obj.name.isEmpty()){ p_obj.name = atomToName(iter.data->name); } - //Now update all the info in the cache - p_obj.primary = (iter.data->primary == 1); - p_obj.automatic = (iter.data->automatic == 1); - p_obj.geometry = QRect(iter.data->x, iter.data->y, iter.data->width, iter.data->height); - p_obj.physicalSizeMM = QSize(iter.data->width_in_millimeters, iter.data->height_in_millimeters); - //Load the "outputs" - p_obj.outputs.clear(); - int out_len = xcb_randr_monitor_info_outputs_length(iter.data); - for(int i=0; i<out_len; i++){ p_obj.outputs << xcb_randr_monitor_info_outputs(iter.data)[i]; } - qDebug() << "Info Loaded:" << p_obj.name; - //break; //Finished with the information for this particular monitor + bool found = false; + for(int i=0; i<2 && !found; i++){ + xcb_randr_get_monitors_cookie_t cookie = xcb_randr_get_monitors_unchecked(QX11Info::connection(), QX11Info::appRootWindow(), (i==0 ? 1 : 0) ); //toggle between active/not monitors + xcb_randr_get_monitors_reply_t *reply = xcb_randr_get_monitors_reply(QX11Info::connection(), cookie, NULL); + if(reply!=0){ + xcb_randr_monitor_info_iterator_t iter = xcb_randr_get_monitors_monitors_iterator(reply); + //qDebug() << "Number of Monitors:" << xcb_randr_get_monitors_monitors_length(reply); + while(iter.rem>0){ + if( p_obj.monitor_atom == iter.data->name || p_obj.name == atomToName(iter.data->name) ){ + loadScreenInfo(&p_obj, iter.data); + found = true; + break; //Finished with the information for this particular monitor + } + xcb_randr_monitor_info_next(&iter); } - xcb_randr_monitor_info_next(&iter); - } - free(reply); - } //end check for reply structure + free(reply); + } //end check for reply structure + } //end loop over active/inactive monitor state } //end loading of active/enabled monitor information - - //Now load any information from the outputs - for(int i=0; i<p_obj.outputs.length(); i++){ - xcb_randr_get_output_info_reply_t *info = xcb_randr_get_output_info_reply(QX11Info::connection(), - xcb_randr_get_output_info_unchecked(QX11Info::connection(), p_obj.outputs[i], QX11Info::appTime()), - NULL); - if(info==0){ continue; } //bad output - //Modes - int mode_len = xcb_randr_get_output_info_modes_length(info); - qDebug() << "Number of Modes:" << mode_len; - if(mode_len<=0){ continue; } //skip this output - not a physical screen which can be used - p_obj.resolutions.clear(); - for(int j=0; j<mode_len; j++){ - xcb_randr_mode_t mode = xcb_randr_get_output_info_modes(info)[j]; - //Still need to convert the mode into the resolution somehow - p_obj.resolutions << QSize(mode,1); - } - } } @@ -203,29 +257,47 @@ void OutputDevice::updateInfoCache(){ // ============================ OutputDeviceList::OutputDeviceList(){ - - QList<xcb_randr_output_t> usedOutputs; + xcb_randr_get_screen_resources_reply_t *reply = xcb_randr_get_screen_resources_reply(QX11Info::connection(), + xcb_randr_get_screen_resources_unchecked(QX11Info::connection(), QX11Info::appRootWindow()), + NULL); + int outputnum = xcb_randr_get_screen_resources_outputs_length(reply); + for(int i=0; i<outputnum; i++){ + xcb_randr_output_t output = xcb_randr_get_screen_resources_outputs(reply)[i]; + //Now display the info about this output + xcb_randr_get_output_info_reply_t *info = xcb_randr_get_output_info_reply(QX11Info::connection(), + xcb_randr_get_output_info_unchecked(QX11Info::connection(), output, QX11Info::appTime()), + NULL); + //Name + QString name = QString::fromLocal8Bit( (char*) xcb_randr_get_output_info_name(info), xcb_randr_get_output_info_name_length(info)); + OutputDevice dev(name); + out_devs.append(dev); //add to the internal list + } + //QList<xcb_atom_t> usedOutputs; //Get the information about all the "enabled" monitors - xcb_randr_get_monitors_cookie_t cookieA = xcb_randr_get_monitors_unchecked(QX11Info::connection(), QX11Info::appRootWindow(), 1); - xcb_randr_get_monitors_reply_t *replyA = xcb_randr_get_monitors_reply(QX11Info::connection(), cookieA, NULL); - if(replyA!=0){ - xcb_randr_monitor_info_iterator_t iter = xcb_randr_get_monitors_monitors_iterator(replyA); - //qDebug() << "Number of Monitors:" << xcb_randr_get_monitors_monitors_length(reply); - while(iter.rem>0){ - //qDebug() << "Found Monitor:"; - //qDebug() << " Index:" << iter.index << "Rem:" << iter.rem; - QString name = atomToName(iter.data->name); - OutputDevice dev(name); - usedOutputs << dev.p_obj.outputs; - - this->append(dev); //add to the internal list - xcb_randr_monitor_info_next(&iter); - } - //Free up any objects we are done with - free(replyA); - } //end loading of active/enabled monitors - -/* + /*for(int i=0; i<2; i++){ //loop over active/inactive monitors + qDebug() << "Scanning For Monitors:" << (i==0 ? "active" : "inactive"); + xcb_randr_get_monitors_cookie_t cookieA = xcb_randr_get_monitors_unchecked(QX11Info::connection(), QX11Info::appRootWindow(), (i==0 ? 1 : 10)); //toggle active/inactive monitors + xcb_randr_get_monitors_reply_t *replyA = xcb_randr_get_monitors_reply(QX11Info::connection(), cookieA, NULL); + if(replyA!=0){ + xcb_randr_monitor_info_iterator_t iter = xcb_randr_get_monitors_monitors_iterator(replyA); + qDebug() << "Number of Monitors:" << xcb_randr_get_monitors_monitors_length(replyA); + while(iter.rem>0){ + //qDebug() << "Found Monitor:"; + //qDebug() << " Index:" << iter.index << "Rem:" << iter.rem; + if(!usedOutputs.contains(iter.data->name)){ + QString name = atomToName(iter.data->name); + OutputDevice dev(name); + usedOutputs << iter.data->name; + out_devs.append(dev); //add to the internal list + } + xcb_randr_monitor_info_next(&iter); + } + //Free up any objects we are done with + free(replyA); + } //end loading of active/enabled monitors + } //end loop over active/inactive monitors + */ + qDebug() << "========================="; //Now get the information about any **UNUSED** monitors/outputs xcb_randr_get_screen_resources_reply_t *reply = xcb_randr_get_screen_resources_reply(QX11Info::connection(), xcb_randr_get_screen_resources_unchecked(QX11Info::connection(), QX11Info::appRootWindow()), @@ -233,21 +305,24 @@ OutputDeviceList::OutputDeviceList(){ int outputnum = xcb_randr_get_screen_resources_outputs_length(reply); qDebug() << "Probing Screen Resources:"; qDebug() << " - Number of Outputs:" << outputnum; - qDebug() << " - Number of CRTC's:" << xcb_randr_get_screen_resources_crtcs_length(reply); - int mode_len =xcb_randr_get_screen_resources_modes_length(reply); - qDebug() << " - Modes:" << mode_len; - for(int m=0; m<mode_len; m++){ + //qDebug() << " - Number of CRTC's:" << xcb_randr_get_screen_resources_crtcs_length(reply); + //int mode_len =xcb_randr_get_screen_resources_modes_length(reply); + //qDebug() << " - Modes:" << mode_len; + /*for(int m=0; m<mode_len; m++){ xcb_randr_mode_info_t mode = xcb_randr_get_screen_resources_modes(reply)[m]; //qDebug() << " -- Mode:" << mode.id; qDebug() << " - Size Option:" << mode.width <<"x"<<mode.height; - } + }*/ for(int i=0; i<outputnum; i++){ xcb_randr_output_t output = xcb_randr_get_screen_resources_outputs(reply)[i]; //Now display the info about this output - xcb_randr_get_output_info_reply_t *info = xcb_randr_get_output_info_reply(QX11Info::connection(), + xcb_randr_get_output_info_reply_t *info = xcb_randr_get_output_info_reply(QX11Info::connection(), xcb_randr_get_output_info_unchecked(QX11Info::connection(), output, QX11Info::appTime()), NULL); qDebug() << "==== Output Information #"+QString::number(i); + //Name + int name_len = xcb_randr_get_output_info_name_length(info); + qDebug() << "Name:" << QString::fromLocal8Bit( (char*) xcb_randr_get_output_info_name(info), name_len); //Modes int mode_len = xcb_randr_get_output_info_modes_length(info); @@ -255,19 +330,11 @@ OutputDeviceList::OutputDeviceList(){ if(mode_len<=0){ continue; } //skip this output - not a physical screen which can be used - //Clones + //Clones qDebug() << "Number of Clones:" << xcb_randr_get_output_info_clones_length(info); - //Names - int name_len = xcb_randr_get_output_info_name_length(info); - qDebug() << "Names:"; //<< atomsToNames( (xcb_atom_t*) xcb_randr_get_output_info_name(info), name_len); - for(int n=0; n<name_len; n++){ - QString name = atomToName( xcb_randr_get_output_info_name(info)[n] ); - qDebug() << " -- " << name; - } - //Properties - xcb_randr_list_output_properties_reply_t *pinfo = xcb_randr_list_output_properties_reply(QX11Info::connection(), + /* xcb_randr_list_output_properties_reply_t *pinfo = xcb_randr_list_output_properties_reply(QX11Info::connection(), xcb_randr_list_output_properties_unchecked(QX11Info::connection(), output), NULL); int pinfo_len = xcb_randr_list_output_properties_atoms_length(pinfo); @@ -286,11 +353,11 @@ OutputDeviceList::OutputDeviceList(){ } free(pinfo); - + */ free(info); } - - free(reply);*/ + + free(reply); } OutputDeviceList::~OutputDeviceList(){ @@ -303,5 +370,11 @@ void OutputDeviceList::setPrimaryMonitor(QString id){ } void OutputDeviceList::disableMonitor(QString id){ - + for(int i=0; i<out_devs.length(); i++){ + if(out_devs[i].ID() == id){ + out_devs[i].disable(); + out_devs[i].updateInfoCache(); + break; + } + } } diff --git a/src-qt5/core/libLumina/LuminaRandR.h b/src-qt5/core/libLumina/LuminaRandR.h index 86c713db..6d205680 100644 --- a/src-qt5/core/libLumina/LuminaRandR.h +++ b/src-qt5/core/libLumina/LuminaRandR.h @@ -16,6 +16,9 @@ #include <QPoint> #include <QRect> #include <QList> +#include <QObject> +#include <QDebug> +#include <QX11Info> // XCB #include "xcb/randr.h" @@ -31,14 +34,15 @@ struct p_objects{ QList<QSize> resolutions; QSize physicalSizeMM; QString name; - QList<xcb_randr_output_t> outputs; + xcb_randr_output_t output; + QList<xcb_randr_mode_t> modes; /*p_objects(){ // Set the defaults for non-default-constructed variables primary = automatic = false; monitor_atom = 0; }*/ - + }; class OutputDevice{ @@ -61,14 +65,16 @@ public: //Information QString ID(); - + bool isEnabled(); bool isPrimary(); bool isAutomatic(); + bool isConnected(); QList<QSize> availableResolutions(); QSize currentResolution(); //could be different from geometry.size() if things like panning/rotation are enabled QRect currentGeometry(); - + QSize physicalSizeMM(); + //Modification bool setAsPrimary(bool); bool disable(); @@ -78,21 +84,31 @@ public: void updateInfoCache(); //Run this after all modification functions to refresh the current info for this device - //Now define a simple public_objects class so that each implementation + //Now define a simple public_objects class so that each implementation // has a storage container for placing semi-private objects as needed //class p_objects; //forward declaration - defined in the .cpp file p_objects p_obj; }; -class OutputDeviceList : public QList<OutputDevice>{ +class OutputDeviceList{ +private: + QList<OutputDevice> out_devs; + public: OutputDeviceList(); ~OutputDeviceList(); + int length(){ return out_devs.length(); } + + OutputDevice* at(int i){ + if(i<out_devs.length()){ return &out_devs[i]; } + return 0; + } + //Simplification functions for dealing with multiple monitors void setPrimaryMonitor(QString id); void disableMonitor(QString id); - //void enableMonitor(QString id, + //void enableMonitor(QString id, QRect geom); }; #endif diff --git a/src-qt5/core/libLumina/LuminaRandR.pri b/src-qt5/core/libLumina/LuminaRandR.pri index 0812819f..1e55b37f 100644 --- a/src-qt5/core/libLumina/LuminaRandR.pri +++ b/src-qt5/core/libLumina/LuminaRandR.pri @@ -4,6 +4,8 @@ QT *= x11extras #X11/XCB includes LIBS *= -lxcb -lxcb-randr +#LIBS *= -lXrandr + SOURCES *= $${PWD}/LuminaRandR-X11.cpp #General API/Header diff --git a/src-qt5/core/libLumina/test/main.cpp b/src-qt5/core/libLumina/test/main.cpp index b2ec9e41..5c6fa67f 100644 --- a/src-qt5/core/libLumina/test/main.cpp +++ b/src-qt5/core/libLumina/test/main.cpp @@ -1,20 +1,26 @@ - -#include "../LuminaRandR.h" #include <QDebug> #include <QApplication> +#include "../LuminaRandR.h" + + int main(int argc, char** argv){ - QApplication A(argc, argv); + QApplication A(argc, argv); qDebug() << "Load Monitor Device Information"; OutputDeviceList devList; qDebug() << "Detected Information:"; for(int i=0; i<devList.length(); i++){ - qDebug() << "["+devList[i].ID()+"]"; - qDebug() << " - isEnabled:" << devList[i].isEnabled(); - qDebug() << " - isPrimary:" << devList[i].isPrimary(); - qDebug() << " - isAutomatic:" << devList[i].isAutomatic(); - qDebug() << " - Current Geometry:" << devList[i].currentGeometry(); - qDebug() << " - Available Resolutions:" << devList[i].availableResolutions(); + qDebug() << "["+devList.at(i)->ID()+"]"; + qDebug() << " - isEnabled:" << devList.at(i)->isEnabled(); + qDebug() << " - isPrimary:" << devList.at(i)->isPrimary(); + qDebug() << " - isAutomatic:" << devList.at(i)->isAutomatic(); + qDebug() << " - Current Geometry:" << devList.at(i)->currentGeometry(); + qDebug() << " - Physical Size (mm):" << devList.at(i)->physicalSizeMM(); + qDebug() << " - Available Resolutions:" << devList.at(i)->availableResolutions(); } + QString disable = "DVI-I-1"; + qDebug() << "Try Disabling Monitor:" << disable; + devList.disableMonitor(disable); + qDebug() << "Finished Test!"; return 0; } diff --git a/src-qt5/core/lumina-desktop/LSession.cpp b/src-qt5/core/lumina-desktop/LSession.cpp index 97f74e66..ebd40030 100644 --- a/src-qt5/core/lumina-desktop/LSession.cpp +++ b/src-qt5/core/lumina-desktop/LSession.cpp @@ -415,8 +415,7 @@ void LSession::updateDesktops(){ QString oldname; for(int i=0; i<old.length(); i++){ QString tmp = old[i].section("/",0,0).section("-",1,-1); //old desktop ID - if(tmp=="default"){ continue; } //always skip this one - else if(lastused.contains(tmp)){ + if(lastused.contains(tmp)){ oldname = tmp; break; //use the first screen that was last used } } diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/applauncher/AppLauncherPlugin.cpp b/src-qt5/core/lumina-desktop/desktop-plugins/applauncher/AppLauncherPlugin.cpp index f751441d..55f05fe9 100644 --- a/src-qt5/core/lumina-desktop/desktop-plugins/applauncher/AppLauncherPlugin.cpp +++ b/src-qt5/core/lumina-desktop/desktop-plugins/applauncher/AppLauncherPlugin.cpp @@ -32,7 +32,7 @@ AppLauncherPlugin::AppLauncherPlugin(QWidget* parent, QString ID) : LDPlugin(par loadButton(); //QTimer::singleShot(0,this, SLOT(loadButton()) ); } - + void AppLauncherPlugin::Cleanup(){ //This is run only when the plugin was forcibly closed/removed @@ -73,7 +73,7 @@ void AppLauncherPlugin::loadButton(){ QAction *tmp = this->contextMenu()->addAction( QString(tr("Launch %1")).arg(file.name), this, SLOT(buttonClicked()) ); ICONS->loadIcon(tmp, file.icon); //See if there are any "actions" listed for this file, and put them in the context menu as needed. - if(!file.actions.isEmpty()){ + if(!file.actions.isEmpty()){ for(int i=0; i<file.actions.length(); i++){ tmp = this->contextMenu()->addAction( file.actions[i].name ); if(ICONS->exists(file.actions[i].icon)){ ICONS->loadIcon(tmp, file.actions[i].icon); } @@ -89,17 +89,17 @@ void AppLauncherPlugin::loadButton(){ button->setWhatsThis(info.absoluteFilePath()); QString iconame; if(info.isDir()){ - if(path.startsWith("/media/")){ + if(path.startsWith("/media/")){ iconame = "drive-removable-media"; //Could add device ID parsing here to determine what "type" of device it is - will be OS-specific though //button->setIcon( LXDG::findIcon("drive-removable-media","") ); } - else{ iconame = "folder"; } //button->setIcon( LXDG::findIcon("folder","") ); + else{ iconame = "folder"; } //button->setIcon( LXDG::findIcon("folder","") ); }else if(LUtils::imageExtensions().contains(info.suffix().toLower()) ){ iconame = info.absoluteFilePath(); //QPixmap pix; - //if(pix.load(path)){ button->setIcon( QIcon(pix.scaled(256,256)) ); } //max size for thumbnails in memory - //else{ iconame = "dialog-cancel"; } //button->setIcon( LXDG::findIcon("dialog-cancel","") ); + //if(pix.load(path)){ button->setIcon( QIcon(pix.scaled(256,256)) ); } //max size for thumbnails in memory + //else{ iconame = "dialog-cancel"; } //button->setIcon( LXDG::findIcon("dialog-cancel","") ); }else{ iconame = LXDG::findAppMimeForFile(path).replace("/","-"); //button->setIcon( QIcon(LXDG::findMimeIcon(path).pixmap(QSize(icosize,icosize)).scaledToHeight(icosize, Qt::SmoothTransformation) ) ); @@ -111,16 +111,22 @@ void AppLauncherPlugin::loadButton(){ }else{ //InValid File button->setWhatsThis(""); - iconID = "quickopen"; //button->setIcon( QIcon(LXDG::findIcon("quickopen","dialog-cancel").pixmap(QSize(icosize,icosize)).scaledToHeight(icosize, Qt::SmoothTransformation) ) ); button->setText( tr("Click to Set") ); if(!watcher->files().isEmpty()){ watcher->removePaths(watcher->files()); } } - if(!iconID.isEmpty()){ - bool updatenow = ICONS->isLoaded(iconID); - ICONS->loadIcon(button, iconID); - if(updatenow){ iconLoaded(iconID); } //will not get a signal - already loaded right now + if(!iconID.isEmpty()){ + if(ICONS->isLoaded(iconID)){ + ICONS->loadIcon(button, iconID); + iconLoaded(iconID); //will not get a signal - already loaded right now + }else{ + //Not loaded yet - verify that the icon exists first + if(!ICONS->exists(iconID) && iconID.contains("/") ){ iconID = iconID.replace("/","-"); } //quick mimetype->icon replacement just in case + if(!ICONS->exists(iconID)){ iconID = "unknown"; } + //Now load the icon + ICONS->loadIcon(button, iconID); + } } //Now adjust the context menu for the button as needed QAction *tmp = 0; diff --git a/src-qt5/core/lumina-desktop/i18n/lumina-desktop_lt.ts b/src-qt5/core/lumina-desktop/i18n/lumina-desktop_lt.ts index 7ed35964..1869e3e0 100644 --- a/src-qt5/core/lumina-desktop/i18n/lumina-desktop_lt.ts +++ b/src-qt5/core/lumina-desktop/i18n/lumina-desktop_lt.ts @@ -261,22 +261,22 @@ <message> <location filename="../BootSplash.cpp" line="63"/> <source>One with the law is a majority.</source> - <translation type="unfinished"></translation> + <translation>Žmogus su įstatymu yra dauguma.</translation> </message> <message> <location filename="../BootSplash.cpp" line="65"/> - <source>Don't expect to build up the weak by pulling down the strong.</source> - <translation type="unfinished"></translation> + <source>Don't expect to build up the weak by pulling down the strong.</source> + <translation>Nesitikėk padrąsinti silpnus, žemindamas stiprius.</translation> </message> <message> <location filename="../BootSplash.cpp" line="67"/> - <source>You can't know too much, but you can say too much.</source> + <source>You can't know too much, but you can say too much.</source> <translation>Negali per daug žinoti, tačiau gali per daug pasakyti.</translation> </message> <message> <location filename="../BootSplash.cpp" line="69"/> <source>Duty is not collective; it is personal.</source> - <translation type="unfinished"></translation> + <translation>Pareiga nėra kolektyvinis dalykas, tai yra asmeninis dalykas.</translation> </message> <message> <location filename="../BootSplash.cpp" line="71"/> @@ -316,7 +316,7 @@ <message> <location filename="../BootSplash.cpp" line="85"/> <source>It does not matter how slowly you go as long as you do not stop.</source> - <translation type="unfinished"></translation> + <translation>Nėra svarbu kaip lėtai judi tol, kol nenustoji judėjęs.</translation> </message> <message> <location filename="../BootSplash.cpp" line="87"/> @@ -326,22 +326,22 @@ <message> <location filename="../BootSplash.cpp" line="89"/> <source>Remember no one can make you feel inferior without your consent.</source> - <translation>Prisiminkite, niekas negali jūsų priversti jaustis menkesniais, be jūsų pačių sutikimo.</translation> + <translation>Prisimink, niekas be tavo paties sutikimo negali priversti tavęs jaustis menkesniu.</translation> </message> <message> <location filename="../BootSplash.cpp" line="91"/> <source>It’s not the years in your life that count. It’s the life in your years.</source> - <translation type="unfinished"></translation> + <translation>Svarbu ne nugyventų gyvenimo metų skaičius, o gyvenimas nugyventuose metuose.</translation> </message> <message> <location filename="../BootSplash.cpp" line="93"/> <source>Either write something worth reading or do something worth writing.</source> - <translation>Arba parašykite ką nors apie ką verta skaityti, arba padarykite ką nors apie ką verta rašyti.</translation> + <translation>Arba parašyk ką nors apie ką verta skaityti, arba padaryk ką nors apie ką verta rašyti.</translation> </message> <message> <location filename="../BootSplash.cpp" line="95"/> <source>The only way to do great work is to love what you do.</source> - <translation type="unfinished"></translation> + <translation>Vienintelis būdas gerai atlikti savo darbą yra mėgti tai ką darai.</translation> </message> <message> <location filename="../BootSplash.cpp" line="97"/> @@ -350,7 +350,7 @@ </message> <message> <location filename="../BootSplash.cpp" line="99"/> - <source>Only two things are infinite, the universe and human stupidity, and I'm not sure about the former.</source> + <source>Only two things are infinite, the universe and human stupidity, and I'm not sure about the former.</source> <translation>Tik du dalykai yra beribiai: visata ir žmogaus kvailumas; tačiau dėl visatos aš nesu tikras.</translation> </message> <message> @@ -360,8 +360,8 @@ </message> <message> <location filename="../BootSplash.cpp" line="103"/> - <source>Do, or do not. There is no 'try'.</source> - <translation type="unfinished"></translation> + <source>Do, or do not. There is no 'try'.</source> + <translation>Daryti arba nedaryti. Nėra "bandyti".</translation> </message> <message> <location filename="../BootSplash.cpp" line="105"/> @@ -376,11 +376,11 @@ <message> <location filename="../BootSplash.cpp" line="109"/> <source>Black holes are where God divided by zero.</source> - <translation type="unfinished"></translation> + <translation>Juodosios skylės yra ten, kur Dievas padalijo iš nulio.</translation> </message> <message> <location filename="../BootSplash.cpp" line="111"/> - <source>It's kind of fun to do the impossible.</source> + <source>It's kind of fun to do the impossible.</source> <translation>Smagu yra daryti tai, kas neįmanoma.</translation> </message> <message> @@ -391,7 +391,7 @@ <message> <location filename="../BootSplash.cpp" line="115"/> <source>A witty saying proves nothing.</source> - <translation type="unfinished"></translation> + <translation>Sąmojingas pasakymas nieko neįrodo.</translation> </message> <message> <location filename="../BootSplash.cpp" line="117"/> @@ -406,7 +406,7 @@ <message> <location filename="../BootSplash.cpp" line="121"/> <source>I have never let my schooling interfere with my education.</source> - <translation type="unfinished"></translation> + <translation>Aš niekada neleidau, kad mano mokslai trukdytų mano išsilavinimui.</translation> </message> <message> <location filename="../BootSplash.cpp" line="123"/> @@ -773,24 +773,24 @@ <message> <location filename="../LDesktop.cpp" line="255"/> <source>Desktop Actions</source> - <translation type="unfinished"></translation> + <translation>Darbalaukio veiksmai</translation> </message> <message> <location filename="../LDesktop.cpp" line="257"/> <location filename="../LDesktop.cpp" line="608"/> <source>New Folder</source> - <translation type="unfinished"></translation> + <translation>Naujas aplankas</translation> </message> <message> <location filename="../LDesktop.cpp" line="258"/> <location filename="../LDesktop.cpp" line="628"/> <source>New File</source> - <translation type="unfinished"></translation> + <translation>Naujas failas</translation> </message> <message> <location filename="../LDesktop.cpp" line="259"/> <source>Paste</source> - <translation type="unfinished"></translation> + <translation>Įdėti</translation> </message> <message> <location filename="../LDesktop.cpp" line="291"/> @@ -827,7 +827,7 @@ <location filename="../LDesktop.cpp" line="634"/> <location filename="../LDesktop.cpp" line="655"/> <source>Desktop</source> - <translation type="unfinished">Darbalaukis</translation> + <translation>Darbalaukis</translation> </message> </context> <context> @@ -874,7 +874,7 @@ <message> <location filename="../panel-plugins/systemdashboard/SysMenuQuick.ui" line="50"/> <source>Volume</source> - <translation type="unfinished"></translation> + <translation>Garsis</translation> </message> <message> <location filename="../panel-plugins/systemdashboard/SysMenuQuick.ui" line="111"/> @@ -1416,22 +1416,22 @@ <message> <location filename="../panel-plugins/systemstart/StartMenu.ui" line="924"/> <source>Suspend</source> - <translation type="unfinished">Pristabdyti</translation> + <translation>Pristabdyti</translation> </message> <message> <location filename="../panel-plugins/systemstart/StartMenu.ui" line="989"/> <source>Restart</source> - <translation type="unfinished">Paleisti iš naujo</translation> + <translation>Paleisti iš naujo</translation> </message> <message> <location filename="../panel-plugins/systemstart/StartMenu.ui" line="1017"/> <source>Power Off</source> - <translation type="unfinished"></translation> + <translation>Išjungti</translation> </message> <message> <location filename="../panel-plugins/systemstart/StartMenu.ui" line="1065"/> <source>Log Out</source> - <translation type="unfinished">Atsijungti</translation> + <translation>Atsijungti</translation> </message> <message> <location filename="../panel-plugins/systemstart/StartMenu.ui" line="262"/> @@ -1501,7 +1501,7 @@ <message> <location filename="../SystemWindow.ui" line="87"/> <source>Power Off</source> - <translation type="unfinished"></translation> + <translation>Išjungti</translation> </message> <message> <location filename="../SystemWindow.ui" line="127"/> diff --git a/src-qt5/core/lumina-desktop/i18n/lumina-desktop_ru.ts b/src-qt5/core/lumina-desktop/i18n/lumina-desktop_ru.ts index 865ccdec..11bf37d6 100644 --- a/src-qt5/core/lumina-desktop/i18n/lumina-desktop_ru.ts +++ b/src-qt5/core/lumina-desktop/i18n/lumina-desktop_ru.ts @@ -265,12 +265,12 @@ </message> <message> <location filename="../BootSplash.cpp" line="65"/> - <source>Don't expect to build up the weak by pulling down the strong.</source> + <source>Don't expect to build up the weak by pulling down the strong.</source> <translation>Не ждите, чтобы создать слабое, потянув вниз сильное.</translation> </message> <message> <location filename="../BootSplash.cpp" line="67"/> - <source>You can't know too much, but you can say too much.</source> + <source>You can't know too much, but you can say too much.</source> <translation>Вы не можете знать слишком много, но вы можете сказать слишком много.</translation> </message> <message> @@ -350,7 +350,7 @@ </message> <message> <location filename="../BootSplash.cpp" line="99"/> - <source>Only two things are infinite, the universe and human stupidity, and I'm not sure about the former.</source> + <source>Only two things are infinite, the universe and human stupidity, and I'm not sure about the former.</source> <translation>Только две вещи бесконечны, вселенная и человеческая глупость.</translation> </message> <message> @@ -360,7 +360,7 @@ </message> <message> <location filename="../BootSplash.cpp" line="103"/> - <source>Do, or do not. There is no 'try'.</source> + <source>Do, or do not. There is no 'try'.</source> <translation>Делай, или не делай. Не пробуй.</translation> </message> <message> @@ -380,7 +380,7 @@ </message> <message> <location filename="../BootSplash.cpp" line="111"/> - <source>It's kind of fun to do the impossible.</source> + <source>It's kind of fun to do the impossible.</source> <translation>Это своего рода забава - сделать невозможное.</translation> </message> <message> @@ -773,24 +773,24 @@ <message> <location filename="../LDesktop.cpp" line="255"/> <source>Desktop Actions</source> - <translation type="unfinished"></translation> + <translation>Действия на рабочем столе</translation> </message> <message> <location filename="../LDesktop.cpp" line="257"/> <location filename="../LDesktop.cpp" line="608"/> <source>New Folder</source> - <translation type="unfinished"></translation> + <translation>Новый каталог</translation> </message> <message> <location filename="../LDesktop.cpp" line="258"/> <location filename="../LDesktop.cpp" line="628"/> <source>New File</source> - <translation type="unfinished"></translation> + <translation>Новый файл</translation> </message> <message> <location filename="../LDesktop.cpp" line="259"/> <source>Paste</source> - <translation type="unfinished"></translation> + <translation>Вставить</translation> </message> <message> <location filename="../LDesktop.cpp" line="291"/> @@ -827,7 +827,7 @@ <location filename="../LDesktop.cpp" line="634"/> <location filename="../LDesktop.cpp" line="655"/> <source>Desktop</source> - <translation type="unfinished">Рабочий стол</translation> + <translation>Рабочий стол</translation> </message> </context> <context> @@ -874,7 +874,7 @@ <message> <location filename="../panel-plugins/systemdashboard/SysMenuQuick.ui" line="50"/> <source>Volume</source> - <translation type="unfinished"></translation> + <translation>Громкость</translation> </message> <message> <location filename="../panel-plugins/systemdashboard/SysMenuQuick.ui" line="111"/> @@ -1416,22 +1416,22 @@ <message> <location filename="../panel-plugins/systemstart/StartMenu.ui" line="924"/> <source>Suspend</source> - <translation type="unfinished">Отложить</translation> + <translation>Отложить</translation> </message> <message> <location filename="../panel-plugins/systemstart/StartMenu.ui" line="989"/> <source>Restart</source> - <translation type="unfinished">Перезагрузить</translation> + <translation>Перезапустить</translation> </message> <message> <location filename="../panel-plugins/systemstart/StartMenu.ui" line="1017"/> <source>Power Off</source> - <translation type="unfinished"></translation> + <translation>Выключить питание</translation> </message> <message> <location filename="../panel-plugins/systemstart/StartMenu.ui" line="1065"/> <source>Log Out</source> - <translation type="unfinished">Завершить Сеанс</translation> + <translation>Завершить Сеанс</translation> </message> <message> <location filename="../panel-plugins/systemstart/StartMenu.ui" line="262"/> @@ -1501,7 +1501,7 @@ <message> <location filename="../SystemWindow.ui" line="87"/> <source>Power Off</source> - <translation type="unfinished"></translation> + <translation>Выключить питание</translation> </message> <message> <location filename="../SystemWindow.ui" line="127"/> diff --git a/src-qt5/core/lumina-desktop/panel-plugins/taskmanager/LTaskManagerPlugin.cpp b/src-qt5/core/lumina-desktop/panel-plugins/taskmanager/LTaskManagerPlugin.cpp index c8e24702..d1647685 100644 --- a/src-qt5/core/lumina-desktop/panel-plugins/taskmanager/LTaskManagerPlugin.cpp +++ b/src-qt5/core/lumina-desktop/panel-plugins/taskmanager/LTaskManagerPlugin.cpp @@ -22,7 +22,7 @@ LTaskManagerPlugin::LTaskManagerPlugin(QWidget *parent, QString id, bool horizon } LTaskManagerPlugin::~LTaskManagerPlugin(){ - + } //============== @@ -31,7 +31,7 @@ LTaskManagerPlugin::~LTaskManagerPlugin(){ void LTaskManagerPlugin::UpdateButtons(){ updating = QDateTime::currentDateTime(); //global time stamp QDateTime ctime = updating; //current thread time stamp - + //Get the current window list QList<WId> winlist = LSession::handle()->XCB->WindowList(); // Ignore the windows which don't want to be listed @@ -119,7 +119,7 @@ void LTaskManagerPlugin::UpdateButtons(){ but->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); }else{ but->setIconSize(QSize(this->width(), this->width())); - but->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + but->setToolButtonStyle(Qt::ToolButtonIconOnly); } this->layout()->addWidget(but); connect(but, SIGNAL(MenuClosed()), this, SIGNAL(MenuClosed())); diff --git a/src-qt5/core/lumina-desktop/panel-plugins/taskmanager/LTaskManagerPlugin.h b/src-qt5/core/lumina-desktop/panel-plugins/taskmanager/LTaskManagerPlugin.h index dabf5a90..0d6d623c 100644 --- a/src-qt5/core/lumina-desktop/panel-plugins/taskmanager/LTaskManagerPlugin.h +++ b/src-qt5/core/lumina-desktop/panel-plugins/taskmanager/LTaskManagerPlugin.h @@ -65,8 +65,8 @@ public slots: QSize sz(this->width(), this->width()); // QSize sz(this->width(), this->height()); //we want to increase the width but not the height of the icons for(int i=0; i<BUTTONS.length(); i++){ - BUTTONS[i]->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); -// BUTTONS[i]->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + BUTTONS[i]->setToolButtonStyle(Qt::ToolButtonIconOnly); +// BUTTONS[i]->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); // if( dpi = 196 ){ int vertsizeicon = ; BUTTONS[i]->setIconSize(vertsizeicon);} // elseif( dpi = 144 ) { int vertsizeicon = ; BUTTONS[i]->setIconSize(vertsizeicon);} // elseif( dpi = 96 ) { int vertsizeicon = ; BUTTONS[i]->setIconSize(vertsizeicon);} diff --git a/src-qt5/core/lumina-open/LFileDialog.cpp b/src-qt5/core/lumina-open/LFileDialog.cpp index a400c60b..ce7c6a6f 100644 --- a/src-qt5/core/lumina-open/LFileDialog.cpp +++ b/src-qt5/core/lumina-open/LFileDialog.cpp @@ -24,7 +24,7 @@ LFileDialog::LFileDialog(QWidget *parent) : QDialog(parent), ui(new Ui::LFileDia } LFileDialog::~LFileDialog(){ - + } // ---------- @@ -67,7 +67,7 @@ QStringList LFileDialog::getPreferredApplications(){ //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++){ @@ -99,8 +99,8 @@ void LFileDialog::setPreferredApplication(QString desktopfile){ newfiles << desktopfile; //Only keep the 5 most recent preferred applications per extension for(int j=0; j<5 && j<files.length(); j++){ - newfiles << files[j]; - } + newfiles << files[j]; + } settings->setValue(keys[i], newfiles.join(":::")); return; } @@ -194,7 +194,7 @@ void LFileDialog::generateAppList(bool shownetwork){ if(tmp.removeDuplicates() > 0 ){ // also put this app in the preferred list //qDebug() << "Mimetype match:" << mimetypes << app[a]->mimeList; - PREFAPPS.append(app[a]->filePath); + PREFAPPS.append(app[a]->filePath); //If this is the first preferred app found - select this app initially if(ui->combo_apps->currentIndex()<=0){ ui->combo_apps->setCurrentIndex(ui->combo_apps->count()-1); } } @@ -248,7 +248,7 @@ void LFileDialog::on_tool_ok_clicked(){ appSelected = true; setDefault = ui->check_default->isChecked(); if(ui->radio_custom->isChecked()){ - appExec = ui->line_bin->text(); + appExec = ui->line_bin->text(); }else if(ui->radio_rec->isChecked()){ //application selected XDGDesktop app(PREFAPPS[ui->combo_rec->currentIndex()]); diff --git a/src-qt5/core/lumina-session/session.cpp b/src-qt5/core/lumina-session/session.cpp index 833a6152..1aa86720 100644 --- a/src-qt5/core/lumina-session/session.cpp +++ b/src-qt5/core/lumina-session/session.cpp @@ -31,19 +31,22 @@ void LSession::stopall(){ void LSession::procFinished(){ //Go through and check the status on all the procs to determine which one finished int stopped = 0; + //qDebug() << "Got Process Stopped Signal:"; for(int i=0; i<PROCS.length(); i++){ if(PROCS[i]->state()==QProcess::NotRunning){ + //qDebug() << " - Stopped:" << PROCS[i]->objectName(); stopped++; if(!stopping){ //See if this process is the main desktop binary if(PROCS[i]->objectName()=="runtime"){ stopall(); } //if(PROCS[i]->program().section("/",-1) == "lumina-desktop"){ stopall(); } //start closing down everything //else{ PROCS[i]->start(QIODevice::ReadOnly); } //restart the process - break; + //break; } } } - if(stopping && stopped==PROCS.length()){ + //qDebug() << " - Final Count:" << stopped << stopping; + if(stopping || stopped==PROCS.length()){ QCoreApplication::exit(0); } } @@ -65,7 +68,7 @@ void LSession::startProcess(QString ID, QString command, QStringList watchfiles) if(!QFile::exists("/etc/machine-id") && !QFile::exists("/var/db/dbus/machine-id")){ if(LUtils::isValidBinary("dbus-uuidgen") && LUtils::runCmd("dbus-uuidgen --ensure") ){ } //good - the UUID was created successfully else if(LUtils::isValidBinary("dbus-launch")){ command.prepend("dbus-launch --exit-with-session "); } - else{ + else{ //create a simple DBUS UUID and put it in the universal-fallback location (OS-independent) // TO-DO - root vs user level permissions issue? qDebug() << "Could not find '/etc/machine-id' or '/var/db/dbus/machine-id': Qt will most likely crash. \nPlease run 'dbus-uuidgen --ensure' with root permissions to generate this file if Lumina does not start properly."; @@ -98,13 +101,13 @@ void LSession::start(bool unified){ keys = keys.replaceInStrings("${XDG_CONFIG_HOME}", QString( getenv("XDG_CONFIG_HOME"))); LUtils::writeFile(confDir+"/fluxbox-init", keys, true); QFile::setPermissions(confDir+"/fluxbox-init", QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::ReadOther | QFile::ReadGroup); - } + } if(!QFile::exists(confDir+"/fluxbox-keys")){ QStringList keys = LUtils::readFile(LOS::LuminaShare()+"/fluxbox-keys"); keys = keys.replaceInStrings("${XDG_CONFIG_HOME}", QString( getenv("XDG_CONFIG_HOME"))); LUtils::writeFile(confDir+"/fluxbox-keys", keys, true); QFile::setPermissions(confDir+"/fluxbox-keys", QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::ReadOther | QFile::ReadGroup); - } + } // FLUXBOX BUG BYPASS: if the ~/.fluxbox dir does not exist, it will ignore the given config file if(!QFile::exists(QDir::homePath()+"/.fluxbox")){ QDir dir; dir.mkpath(QDir::homePath()+"/.fluxbox"); @@ -129,7 +132,7 @@ void LSession::start(bool unified){ bool hasAccel =! LUtils::getCmdOutput("glxinfo -B").filter("direct rendering:").filter("Yes").isEmpty(); qDebug() << "Detected GPU Acceleration:" << hasAccel; QStringList info = LUtils::readFile(set); - for(int i=0; i<info.length(); i++){ + for(int i=0; i<info.length(); i++){ if(info[i].section("=",0,0).simplified()=="backend"){ info[i] = QString("backend = \"")+ (hasAccel ? "glx" : "xrender")+"\""; break; } //replace this line } LUtils::writeFile(set, info, true); @@ -142,7 +145,7 @@ void LSession::start(bool unified){ } else { if(!LUtils::isValidBinary(WM)){ exit(1); - } + } startProcess("wm", WM); } //Desktop Next 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() |