diff options
Diffstat (limited to 'src-qt5')
50 files changed, 1652 insertions, 469 deletions
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() |