aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--port-files/pkg-plist63
-rw-r--r--src-qt5/core-utils/lumina-config/LPlugins.cpp9
-rw-r--r--src-qt5/core-utils/lumina-config/mainUI.cpp10
-rw-r--r--src-qt5/core-utils/lumina-xconfig/MainUI.cpp18
-rw-r--r--src-qt5/core-utils/lumina-xconfig/MainUI.h12
-rw-r--r--src-qt5/core-utils/lumina-xconfig/MainUI.ui13
-rw-r--r--src-qt5/core-utils/lumina-xconfig/ScreenSettings.cpp191
-rw-r--r--src-qt5/core-utils/lumina-xconfig/ScreenSettings.h49
-rw-r--r--src-qt5/core-utils/lumina-xconfig/lumina-xconfig.pro6
-rw-r--r--src-qt5/core-utils/lumina-xconfig/main.cpp16
-rw-r--r--src-qt5/core/libLumina/LuminaOS-Debian.cpp2
-rw-r--r--src-qt5/core/libLumina/LuminaOS-DragonFly.cpp6
-rw-r--r--src-qt5/core/libLumina/LuminaOS-FreeBSD.cpp7
-rw-r--r--src-qt5/core/libLumina/LuminaOS-Gentoo.cpp2
-rw-r--r--src-qt5/core/libLumina/LuminaOS-Linux.cpp2
-rw-r--r--src-qt5/core/libLumina/LuminaOS-NetBSD.cpp8
-rw-r--r--src-qt5/core/libLumina/LuminaOS-OpenBSD.cpp2
-rw-r--r--src-qt5/core/libLumina/LuminaOS-kFreeBSD.cpp2
-rw-r--r--src-qt5/core/libLumina/LuminaOS-template.cpp4
-rw-r--r--src-qt5/core/libLumina/LuminaOS.h3
-rw-r--r--src-qt5/core/libLumina/LuminaUtils.cpp77
-rw-r--r--src-qt5/core/libLumina/LuminaUtils.h5
-rw-r--r--src-qt5/core/libLumina/LuminaX11.h14
-rw-r--r--src-qt5/core/libLumina/LuminaXDG.cpp34
-rw-r--r--src-qt5/core/lumina-desktop/AppMenu.cpp2
-rw-r--r--src-qt5/core/lumina-desktop/LDesktop.cpp2
-rw-r--r--src-qt5/core/lumina-desktop/LWinInfo.cpp4
-rw-r--r--src-qt5/core/lumina-desktop/defaults/luminaDesktop.conf52
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/NewDP.h3
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/calendar/CalendarPlugin.h1
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/desktop-plugins.pri11
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSFeedPlugin.cpp363
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSFeedPlugin.h72
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSFeedPlugin.ui545
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSObjects.cpp275
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSObjects.h101
-rw-r--r--src-qt5/core/lumina-desktop/panel-plugins/appmenu/LAppMenuPlugin.cpp3
-rw-r--r--src-qt5/core/lumina-desktop/panel-plugins/systemstart/LStartButton.cpp3
-rw-r--r--src-qt5/core/lumina-desktop/panel-plugins/taskmanager/LTaskButton.cpp8
-rw-r--r--src-qt5/core/lumina-open/LFileDialog.cpp8
-rw-r--r--src-qt5/core/lumina-open/main.cpp6
-rw-r--r--src-qt5/core/lumina-session/main.cpp4
-rw-r--r--src-qt5/desktop-utils/lumina-fm/FODialog.cpp2
-rw-r--r--src-qt5/desktop-utils/lumina-fm/MainUI.cpp6
-rw-r--r--src-qt5/desktop-utils/lumina-fm/lumina-fm.pro7
-rw-r--r--src-qt5/desktop-utils/lumina-terminal/TerminalWidget.cpp2
46 files changed, 1924 insertions, 111 deletions
diff --git a/port-files/pkg-plist b/port-files/pkg-plist
index 4dd64830..0c983ff1 100644
--- a/port-files/pkg-plist
+++ b/port-files/pkg-plist
@@ -7,6 +7,7 @@ bin/lumina-search
bin/lumina-info
bin/lumina-xconfig
bin/lumina-fileinfo
+bin/lumina-textedit
etc/luminaDesktop.conf.dist
lib/libLuminaUtils.so
lib/libLuminaUtils.so.1
@@ -426,6 +427,68 @@ share/Lumina-DE/i18n/lumina-search_zh_CN.qm
share/Lumina-DE/i18n/lumina-search_zh_HK.qm
share/Lumina-DE/i18n/lumina-search_zh_TW.qm
share/Lumina-DE/i18n/lumina-search_zu.qm
+share/Lumina-DE/i18n/lumina-textedit_af.qm
+share/Lumina-DE/i18n/lumina-textedit_ar.qm
+share/Lumina-DE/i18n/lumina-textedit_az.qm
+share/Lumina-DE/i18n/lumina-textedit_bg.qm
+share/Lumina-DE/i18n/lumina-textedit_bn.qm
+share/Lumina-DE/i18n/lumina-textedit_bs.qm
+share/Lumina-DE/i18n/lumina-textedit_ca.qm
+share/Lumina-DE/i18n/lumina-textedit_cs.qm
+share/Lumina-DE/i18n/lumina-textedit_cy.qm
+share/Lumina-DE/i18n/lumina-textedit_da.qm
+share/Lumina-DE/i18n/lumina-textedit_de.qm
+share/Lumina-DE/i18n/lumina-textedit_el.qm
+share/Lumina-DE/i18n/lumina-textedit_en_GB.qm
+share/Lumina-DE/i18n/lumina-textedit_en_ZA.qm
+share/Lumina-DE/i18n/lumina-textedit_es.qm
+share/Lumina-DE/i18n/lumina-textedit_et.qm
+share/Lumina-DE/i18n/lumina-textedit_eu.qm
+share/Lumina-DE/i18n/lumina-textedit_fa.qm
+share/Lumina-DE/i18n/lumina-textedit_fi.qm
+share/Lumina-DE/i18n/lumina-textedit_fr.qm
+share/Lumina-DE/i18n/lumina-textedit_fr_CA.qm
+share/Lumina-DE/i18n/lumina-textedit_gl.qm
+share/Lumina-DE/i18n/lumina-textedit_he.qm
+share/Lumina-DE/i18n/lumina-textedit_hi.qm
+share/Lumina-DE/i18n/lumina-textedit_hr.qm
+share/Lumina-DE/i18n/lumina-textedit_hu.qm
+share/Lumina-DE/i18n/lumina-textedit_id.qm
+share/Lumina-DE/i18n/lumina-textedit_is.qm
+share/Lumina-DE/i18n/lumina-textedit_it.qm
+share/Lumina-DE/i18n/lumina-textedit_ja.qm
+share/Lumina-DE/i18n/lumina-textedit_ka.qm
+share/Lumina-DE/i18n/lumina-textedit_ko.qm
+share/Lumina-DE/i18n/lumina-textedit_lt.qm
+share/Lumina-DE/i18n/lumina-textedit_lv.qm
+share/Lumina-DE/i18n/lumina-textedit_mk.qm
+share/Lumina-DE/i18n/lumina-textedit_mn.qm
+share/Lumina-DE/i18n/lumina-textedit_ms.qm
+share/Lumina-DE/i18n/lumina-textedit_mt.qm
+share/Lumina-DE/i18n/lumina-textedit_nb.qm
+share/Lumina-DE/i18n/lumina-textedit_nl.qm
+share/Lumina-DE/i18n/lumina-textedit_pa.qm
+share/Lumina-DE/i18n/lumina-textedit_pl.qm
+share/Lumina-DE/i18n/lumina-textedit_pt.qm
+share/Lumina-DE/i18n/lumina-textedit_pt_BR.qm
+share/Lumina-DE/i18n/lumina-textedit_ro.qm
+share/Lumina-DE/i18n/lumina-textedit_ru.qm
+share/Lumina-DE/i18n/lumina-textedit_sk.qm
+share/Lumina-DE/i18n/lumina-textedit_sl.qm
+share/Lumina-DE/i18n/lumina-textedit_sr.qm
+share/Lumina-DE/i18n/lumina-textedit_sv.qm
+share/Lumina-DE/i18n/lumina-textedit_sw.qm
+share/Lumina-DE/i18n/lumina-textedit_ta.qm
+share/Lumina-DE/i18n/lumina-textedit_tg.qm
+share/Lumina-DE/i18n/lumina-textedit_th.qm
+share/Lumina-DE/i18n/lumina-textedit_tr.qm
+share/Lumina-DE/i18n/lumina-textedit_uk.qm
+share/Lumina-DE/i18n/lumina-textedit_uz.qm
+share/Lumina-DE/i18n/lumina-textedit_vi.qm
+share/Lumina-DE/i18n/lumina-textedit_zh_CN.qm
+share/Lumina-DE/i18n/lumina-textedit_zh_HK.qm
+share/Lumina-DE/i18n/lumina-textedit_zh_TW.qm
+share/Lumina-DE/i18n/lumina-textedit_zu.qm
share/Lumina-DE/i18n/lumina-info_af.qm
share/Lumina-DE/i18n/lumina-info_ar.qm
share/Lumina-DE/i18n/lumina-info_az.qm
diff --git a/src-qt5/core-utils/lumina-config/LPlugins.cpp b/src-qt5/core-utils/lumina-config/LPlugins.cpp
index 629171e1..03490216 100644
--- a/src-qt5/core-utils/lumina-config/LPlugins.cpp
+++ b/src-qt5/core-utils/lumina-config/LPlugins.cpp
@@ -211,6 +211,13 @@ void LPlugins::LoadDesktopPlugins(){
info.ID = "systemmonitor";
info.icon = "cpu";
DESKTOP.insert(info.ID, info);
+ //RSS Reader Plugin
+ info = LPI(); //clear it
+ info.name = QObject::tr("RSS Reader");
+ info.description = QObject::tr("Monitor RSS Feeds (Requires internet connection)");
+ info.ID = "rssreader";
+ info.icon = "application-rss+xml";
+ DESKTOP.insert(info.ID, info);
//Available QtQuick scripts
/*QStringList quickID = LUtils::listQuickPlugins();
for(int i=0; i<quickID.length(); i++){
@@ -358,4 +365,4 @@ void LPlugins::LoadColorItems(){
info.description = QObject::tr("Color used for highlighting an item (more subdued).");
info.ID = "HIGHLIGHTDISABLECOLOR";
COLORS.insert(info.ID, info);
-} \ No newline at end of file
+}
diff --git a/src-qt5/core-utils/lumina-config/mainUI.cpp b/src-qt5/core-utils/lumina-config/mainUI.cpp
index 5062a5ef..bd2bf695 100644
--- a/src-qt5/core-utils/lumina-config/mainUI.cpp
+++ b/src-qt5/core-utils/lumina-config/mainUI.cpp
@@ -1136,7 +1136,8 @@ void MainUI::changeDefaultEmail(){
desk.filePath="";
}
//save the new app setting and adjust the button appearance
- appsettings->setValue("default/email", desk.filePath);
+ LXDG::setDefaultAppForMime("application/email",desk.filePath);
+ // appsettings->setValue("default/email", desk.filePath);
QString tmp = desk.filePath;
if(tmp.endsWith(".desktop")){
bool ok = false;
@@ -1200,7 +1201,8 @@ void MainUI::changeDefaultTerminal(){
desk.filePath="xterm";
}
//save the new app setting and adjust the button appearance
- sessionsettings->setValue("default-terminal", desk.filePath);
+ LXDG::setDefaultAppForMime("application/terminal",desk.filePath);
+ //sessionsettings->setValue("default-terminal", desk.filePath);
QString tmp = desk.filePath;
if(tmp.endsWith(".desktop")){
bool ok = false;
@@ -1249,7 +1251,7 @@ void MainUI::loadDefaultSettings(){
ui->tool_default_filemanager->setIcon( LXDG::findIcon("application-x-executable","") );
}
// - Default Terminal
- tmp = sessionsettings->value("default-terminal", "xterm").toString();
+ tmp =LXDG::findDefaultAppForMime("application/terminal"); //sessionsettings->value("default-terminal", "xterm").toString();
if( !QFile::exists(tmp) && !LUtils::isValidBinary(tmp) ){ qDebug() << "Invalid Settings:" << tmp; tmp.clear(); } //invalid settings
if(tmp.endsWith(".desktop")){
bool ok = false;
@@ -1293,7 +1295,7 @@ void MainUI::loadDefaultSettings(){
ui->tool_default_webbrowser->setIcon( LXDG::findIcon("application-x-executable","") );
}
// - Default Email Client
- tmp = appsettings->value("default/email", "").toString();
+ tmp = LXDG::findDefaultAppForMime("application/email"); //appsettings->value("default/email", "").toString();
if( !QFile::exists(tmp) && !LUtils::isValidBinary(tmp) ){ qDebug() << "Invalid Settings:" << tmp; tmp.clear(); } //invalid settings
if(tmp.endsWith(".desktop")){
bool ok = false;
diff --git a/src-qt5/core-utils/lumina-xconfig/MainUI.cpp b/src-qt5/core-utils/lumina-xconfig/MainUI.cpp
index f4aa1c49..2aed4d30 100644
--- a/src-qt5/core-utils/lumina-xconfig/MainUI.cpp
+++ b/src-qt5/core-utils/lumina-xconfig/MainUI.cpp
@@ -54,6 +54,7 @@ QStringList MainUI::currentOpts(){
for(int i=0; i<SCREENS.length(); i++){
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){
//Get the ID of the previous screen
QString id;
@@ -79,8 +80,8 @@ ScreenInfo MainUI::currentScreenInfo(){
void MainUI::UpdateScreens(){
//First probe the server for current screens
- SCREENS.clear();
- QStringList info = LUtils::getCmdOutput("xrandr -q");
+ SCREENS = RRSettings::CurrentScreens();
+ /*QStringList info = LUtils::getCmdOutput("xrandr -q");
ScreenInfo cscreen;
for(int i=0; i<info.length(); i++){
if(info[i].contains("connected") ){
@@ -105,6 +106,7 @@ void MainUI::UpdateScreens(){
UpdateScreens();
return;
}else if( !devres.isEmpty() ){
+ cscreen.isprimary = info[i].contains(" primary ");
//Device that is connected and attached (has a resolution)
qDebug() << "Create new Screen entry:" << dev << devres;
cscreen.ID = dev;
@@ -121,9 +123,9 @@ void MainUI::UpdateScreens(){
//available resolution for a device
cscreen.resList << info[i].section("\t",0,0,QString::SectionSkipEmpty);
}
- }
+ } //end loop over info lines
if(!cscreen.ID.isEmpty()){ SCREENS << cscreen; } //make sure to add the last screen to the array
-
+ */
//Now go through the screens and arrange them in order from left->right in the UI
bool found = true;
int xoffset = 0; //start at 0
@@ -138,7 +140,7 @@ void MainUI::UpdateScreens(){
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 currrent order to it
+ SCREENS[i].order = cnum; //assign the current order to it
cnum++; //get ready for the next one
QListWidgetItem *it = new QListWidgetItem();
it->setTextAlignment(Qt::AlignCenter);
@@ -170,6 +172,7 @@ void MainUI::UpdateScreens(){
}
if(ui->list_screens->currentItem()==0){ ui->list_screens->setCurrentRow(0); }
ScreenSelected(); //update buttons
+ RRSettings::SaveScreens(SCREENS);
}
void MainUI::ScreenSelected(){
@@ -196,6 +199,7 @@ void MainUI::ScreenSelected(){
else{ui->combo_resolution->addItem(res, res); }
if(cur.resList[i].contains(cres)){ ui->combo_resolution->setCurrentIndex(i); }
}
+ ui->check_primary->setChecked( cur.isprimary );
}
}
@@ -282,14 +286,16 @@ void MainUI::ApplyChanges(){
if(newres.isEmpty()){ return; } //nothing to do
//qDebug() << "Apply Screen Changes" << it->whatsThis() << "->" << newres;
//Adjust the order of the two screens
+ bool setprimary = ui->check_primary->isChecked();
for(int i=0; i<SCREENS.length(); i++){
if(SCREENS[i].ID == it->whatsThis()){
SCREENS[i].geom.setWidth(newres.section("x",0,0).toInt());
SCREENS[i].geom.setHeight(newres.section("x",1,1).toInt());
}
+ if(setprimary){ SCREENS[i].isprimary = SCREENS[i].ID==it->whatsThis(); }
}
//Now run the command
QStringList opts = currentOpts();
LUtils::runCmd("xrandr", opts);
QTimer::singleShot(500, this, SLOT(UpdateScreens()) );
-} \ No newline at end of file
+}
diff --git a/src-qt5/core-utils/lumina-xconfig/MainUI.h b/src-qt5/core-utils/lumina-xconfig/MainUI.h
index 0563c4ca..b8be8701 100644
--- a/src-qt5/core-utils/lumina-xconfig/MainUI.h
+++ b/src-qt5/core-utils/lumina-xconfig/MainUI.h
@@ -12,17 +12,7 @@
#include <QString>
#include <QList>
-class ScreenInfo{
- public:
- QString ID;
- QRect geom; //screen geometry
- int order; //left to right
- QStringList resList;
- ScreenInfo(){
- order = -1; //initial value is invalid
- }
- ~ScreenInfo(){}
-};
+#include "ScreenSettings.h"
namespace Ui{
class MainUI;
diff --git a/src-qt5/core-utils/lumina-xconfig/MainUI.ui b/src-qt5/core-utils/lumina-xconfig/MainUI.ui
index c1c4b614..de1cc18d 100644
--- a/src-qt5/core-utils/lumina-xconfig/MainUI.ui
+++ b/src-qt5/core-utils/lumina-xconfig/MainUI.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>408</width>
- <height>316</height>
+ <height>321</height>
</rect>
</property>
<property name="windowTitle">
@@ -142,7 +142,7 @@
</item>
</layout>
</item>
- <item row="1" column="1">
+ <item row="2" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -155,7 +155,7 @@
</property>
</spacer>
</item>
- <item row="2" column="1">
+ <item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<spacer name="horizontalSpacer_2">
@@ -182,6 +182,13 @@
</item>
</layout>
</item>
+ <item row="1" column="1">
+ <widget class="QCheckBox" name="check_primary">
+ <property name="text">
+ <string>Primary Screen</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
<widget class="QWidget" name="tab_new">
diff --git a/src-qt5/core-utils/lumina-xconfig/ScreenSettings.cpp b/src-qt5/core-utils/lumina-xconfig/ScreenSettings.cpp
new file mode 100644
index 00000000..c9a833c3
--- /dev/null
+++ b/src-qt5/core-utils/lumina-xconfig/ScreenSettings.cpp
@@ -0,0 +1,191 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2016, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "ScreenSettings.h"
+#include <LuminaUtils.h>
+#include <QDebug>
+#include <QSettings>
+
+//Reset current screen config to match previously-saved settings
+void RRSettings::ApplyPrevious(){
+ QSettings set("lumina-desktop","lumina-xconfig");
+ set.beginGroup("MonitorSettings");
+ //Setup a couple lists
+ QStringList devs = set.childGroups(); //known/saved devices
+ QList<ScreenInfo> screens = RRSettings::CurrentScreens();
+ QStringList lastactive = set.value("lastActive",QStringList()).toStringList();
+ //Now go through all the saved settings and put that info into the array
+ QString primary;
+ QStringList avail;
+ for(int i=0; i<screens.length(); i++){
+ //if(screens[i].order>=0){screens[i].order = -1; } //reset all screen orders (need to re-check all)
+ if(devs.contains(screens[i].ID) && screens[i].isavailable){ //only load settings for monitors which are currently attached
+ set.beginGroup(screens[i].ID);
+ screens[i].geom = set.value("geometry", QRect()).toRect();
+ screens[i].isprimary = set.value("isprimary", false).toBool();
+ if(screens[i].isprimary){ primary = screens[i].ID; }
+ screens[i].isactive = lastactive.contains(screens[i].ID);
+ screens[i].order = (screens[i].isactive ? -1 : -3); //check/ignore
+ set.endGroup();
+ }else if(screens[i].isavailable){
+ screens[i].order = -2; //needs activation/placement
+ }else{
+ screens[i].order = -3; //ignored
+ }
+ //Now clean up the list as needed
+ if(screens[i].order < -2){ screens.removeAt(i); i--; } //just remove it (less to loop through later)
+ else{ avail << screens[i].ID; } //needed for some checks later - make it simple
+ }
+ //NOTE ABOUT orders: -1: check geom, -2: auto-add to end, -3: ignored
+
+ //Quick checks for simple systems - just use current X config as-is
+ if(devs.isEmpty() && (avail.filter("LVDS").isEmpty() || screens.length()==1) ){ return; }
+
+ //Typical ID's: LVDS-[], DVI-I-[], DP-[], HDMI-[], VGA-[]
+ //"LVDS" is the built-in laptop display normally
+ if(primary.isEmpty()){
+ QStringList priority; priority << "LVDS" << "DP" << "HDMI" << "DVI" << "VGA";
+ for(int i=0; i<priority.length() && primary.isEmpty(); i++){
+ QStringList filter = avail.filter(priority[i]);
+ if(!filter.isEmpty()){ filter.sort(); primary = filter.first(); }
+ }
+ if(primary.isEmpty()){ primary = avail.first(); }
+ }
+ //Ensure only one monitor is primary, and reset a few flags
+ for(int i=0; i<screens.length(); i++){
+ if(screens[i].ID!=primary){ screens[i].isprimary = false; }
+ screens[i].isactive = true; //we want all these monitors to be active eventually
+ }
+ // Handle all the available monitors
+ int handled = 0;
+ int cx = 0; //current x point
+ while(handled<screens.length()){
+ //Go through horizontally and place monitors (TO-DO: Vertical placement not handled yet)
+ int next = -1;
+ int diff = -1;
+ for(int i=0; i<screens.length(); i++){
+ if(screens[i].order==-1){
+ if(diff<0 || ((screens[i].geom.x()-cx) < diff)){
+ diff = screens[i].geom.x()-cx;
+ next = i;
+ }
+ }
+ }//end loop over screens
+ if(next<0){
+ //Go through and start adding the non-assigned screens to the end
+ for(int i=0; i<screens.length(); i++){
+ if(screens[i].order==-2){
+ if(diff<0 || ((screens[i].geom.x()-cx) < diff)){
+ diff = screens[i].geom.x()-cx;
+ next = i;
+ }
+ }
+ } //end loop over screens
+ }
+ if(next>=0){
+ cx+=screens[next].geom.width();
+ screens[next].order = handled; handled++;
+ }else{
+ //Still missing monitors (vertical alignment?)
+ qDebug() << "Unhandled Monitors:" << screens.length()-handled;
+ break;
+ }
+ }
+ //Now reset the display with xrandr
+ RRSettings::Apply(screens);
+}
+
+//Read the current screen config from xrandr
+QList<ScreenInfo> RRSettings::CurrentScreens(){
+ QList<ScreenInfo> SCREENS;
+ QStringList info = LUtils::getCmdOutput("xrandr -q");
+ ScreenInfo cscreen;
+ for(int i=0; i<info.length(); i++){
+ if(info[i].contains("connected") ){
+ //qDebug() << "xrandr info:" << info[i];
+ if(!cscreen.ID.isEmpty()){
+ SCREENS << cscreen; //current screen finished - save it into the array
+ 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
+ QString devres = info[i].section(" ",2,2, QString::SectionSkipEmpty);
+ if(!devres.contains("x")){ devres = info[i].section(" ",3,3,QString::SectionSkipEmpty); }
+ if(!devres.contains("x")){ devres.clear(); }
+ qDebug() << " - ID:" <<dev << "Current Geometry:" << devres;
+ //qDebug() << " - Res:" << devres;
+ if( !devres.contains("x") || !devres.contains("+") ){ devres.clear(); }
+ //qDebug() << " - Res (modified):" << devres;
+ if(info[i].contains(" disconnected ") && !devres.isEmpty() ){
+ //Device disconnected, but still active on X
+ cscreen.isavailable = false;
+ cscreen.isactive = true;
+ }else if( !devres.isEmpty() ){
+ cscreen.isprimary = info[i].contains(" primary ");
+ //Device that is connected and attached (has a resolution)
+ qDebug() << "Create new Screen entry:" << dev << devres;
+ 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() );
+ cscreen.isavailable = true;
+ cscreen.isactive = true;
+ }else if(info[i].contains(" connected")){
+ //Device that is connected, but not attached
+ qDebug() << "Create new Screen entry:" << dev << "none";
+ cscreen.ID = dev;
+ cscreen.order = -2; //flag this right now as a non-active screen
+ cscreen.isavailable = true;
+ cscreen.isactive = false;
+ }
+ }else if( !cscreen.ID.isEmpty() && info[i].section("\t",0,0,QString::SectionSkipEmpty).contains("x")){
+ //available resolution for a device
+ cscreen.resList << info[i].section("\t",0,0,QString::SectionSkipEmpty);
+ }
+ } //end loop over primary info lines
+ if(!cscreen.ID.isEmpty()){ SCREENS << cscreen; } //make sure to add the last screen to the array
+ return SCREENS;
+}
+
+//Save the screen config for later
+bool RRSettings::SaveScreens(QList<ScreenInfo> screens){
+ QSettings set("lumina-desktop","lumina-xconfig");
+ set.beginGroup("MonitorSettings");
+ //Setup a couple lists
+ QStringList olddevs = set.childGroups();
+ QStringList active;
+ //Now go through all the current screens and save that info
+ for(int i=0; i<screens.length(); i++){
+ olddevs.removeAll(screens[i].ID); //this is still a valid device
+ if(screens[i].isactive){ active << screens[i].ID; }
+ set.beginGroup(screens[i].ID);
+ set.setValue("geometry", screens[i].geom);
+ set.setValue("isprimary", screens[i].isprimary);
+ set.endGroup();
+ }
+ set.setValue("lastActive",active);
+ //Clean up any old device settings (no longer available for this hardware)
+ for(int i=0; i<olddevs.length(); i++){
+ set.remove(olddevs[i]);
+ }
+ return true;
+}
+
+//Apply screen configuration
+void RRSettings::Apply(QList<ScreenInfo> screens){
+ //Read all the settings and create the xrandr options to maintain these settings
+ QStringList opts;
+ qDebug() << "Apply:" << screens.length();
+ for(int i=0; i<screens.length(); i++){
+ qDebug() << " -- Screen:" << i << screens[i].ID << screens[i].isactive << screens[i].order;
+ if(screens[i].order <0 || !screens[i].isactive){ 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());
+ //opts << "--pos" << QString::number(screens[i].geom.x())+"x"+QString::number(screens[i].geom.y());
+ if(screens[i].isprimary){ opts << "--primary"; }
+ }
+ qDebug() << "Run command: xrandr" << opts;
+ LUtils::runCmd("xrandr", opts);
+}
diff --git a/src-qt5/core-utils/lumina-xconfig/ScreenSettings.h b/src-qt5/core-utils/lumina-xconfig/ScreenSettings.h
new file mode 100644
index 00000000..770c4f95
--- /dev/null
+++ b/src-qt5/core-utils/lumina-xconfig/ScreenSettings.h
@@ -0,0 +1,49 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2016, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_SCREEN_SETTINGS_BACKEND_H
+#define _LUMINA_SCREEN_SETTINGS_BACKEND_H
+
+#include <QString>
+#include <QList>
+#include <QRect>
+
+class ScreenInfo{
+ public:
+ QString ID;
+ QRect geom; //screen geometry
+ bool isprimary;
+ bool isactive;
+ bool isavailable;
+ int order; //left to right
+ QStringList resList;
+
+ //Initial Defaults
+ ScreenInfo(){
+ order = -1; //initial value is invalid
+ isprimary = false;
+ isactive = false;
+ isavailable = false;
+ }
+ ~ScreenInfo(){}
+};
+
+class RRSettings{
+public:
+ //Reset current screen config to match previously-saved settings
+ static void ApplyPrevious(); //generally performed on startup of the desktop
+
+ //Read the current screen config from xrandr
+ static QList<ScreenInfo> CurrentScreens(); //reads xrandr information
+
+ //Save the screen config for later
+ static bool SaveScreens(QList<ScreenInfo> screens);
+
+ //Apply screen configuration
+ static void Apply(QList<ScreenInfo> screens);
+};
+
+#endif
diff --git a/src-qt5/core-utils/lumina-xconfig/lumina-xconfig.pro b/src-qt5/core-utils/lumina-xconfig/lumina-xconfig.pro
index 676f237c..2661c19b 100644
--- a/src-qt5/core-utils/lumina-xconfig/lumina-xconfig.pro
+++ b/src-qt5/core-utils/lumina-xconfig/lumina-xconfig.pro
@@ -9,9 +9,11 @@ target.path = $${L_BINDIR}
TEMPLATE = app
SOURCES += main.cpp \
- mainUI.cpp
+ mainUI.cpp \
+ ScreenSettings.cpp
-HEADERS += mainUI.h
+HEADERS += mainUI.h \
+ ScreenSettings.h
FORMS += mainUI.ui
diff --git a/src-qt5/core-utils/lumina-xconfig/main.cpp b/src-qt5/core-utils/lumina-xconfig/main.cpp
index 699665fb..f30486f4 100644
--- a/src-qt5/core-utils/lumina-xconfig/main.cpp
+++ b/src-qt5/core-utils/lumina-xconfig/main.cpp
@@ -9,20 +9,18 @@
#include <LuminaUtils.h>
#include <LuminaSingleApplication.h>
+#include "ScreenSettings.h"
int main(int argc, char ** argv)
{
- /*QStringList in;
+ bool CLIdone = false;
for(int i=1; i<argc; i++){ //skip the first arg (app binary)
- QString path = argv[i];
- if(path=="."){
- //Insert the current working directory
- in << QDir::currentPath();
- }else{
- if(!path.startsWith("/")){ path.prepend(QDir::currentPath()+"/"); }
- in << path;
+ if(QString(argv[i]) == "--reset-monitors"){
+ RRSettings::ApplyPrevious();
+ CLIdone = true;
+ break;
}
}
- if(in.isEmpty()){ in << QDir::homePath(); }*/
+ if(CLIdone){ return 0; }
LTHEME::LoadCustomEnvSettings();
LSingleApplication a(argc, argv, "lumina-xconfig"); //loads translations inside constructor
if( !a.isPrimaryProcess()){ return 0; }
diff --git a/src-qt5/core/libLumina/LuminaOS-Debian.cpp b/src-qt5/core/libLumina/LuminaOS-Debian.cpp
index 75aad108..cb8e9cdd 100644
--- a/src-qt5/core/libLumina/LuminaOS-Debian.cpp
+++ b/src-qt5/core/libLumina/LuminaOS-Debian.cpp
@@ -24,6 +24,8 @@ QString LOS::SysPrefix(){ return "/"; } //Prefix for system
//OS-specific application shortcuts (*.desktop files)
QString LOS::ControlPanelShortcut(){ return ""; } //system control panel
QString LOS::AppStoreShortcut(){ return LOS::AppPrefix() + "/share/applications/synaptic.desktop"; } //graphical app/pkg manager
+//OS-specific RSS feeds (Format: QStringList[ <name>::::<url> ]; )
+QStringList LOS::RSSFeeds(){ return QStringList(); }
// ==== ExternalDevicePaths() ====
QStringList LOS::ExternalDevicePaths(){
diff --git a/src-qt5/core/libLumina/LuminaOS-DragonFly.cpp b/src-qt5/core/libLumina/LuminaOS-DragonFly.cpp
index b98a36ee..919c88e5 100644
--- a/src-qt5/core/libLumina/LuminaOS-DragonFly.cpp
+++ b/src-qt5/core/libLumina/LuminaOS-DragonFly.cpp
@@ -74,6 +74,12 @@ QString LOS::SysPrefix(){ return "/usr/"; } //Prefix for system
//OS-specific application shortcuts (*.desktop files)
QString LOS::ControlPanelShortcut(){ return ""; } //system control panel
QString LOS::AppStoreShortcut(){ return ""; } //graphical app/pkg manager
+//OS-specific RSS feeds (Format: QStringList[ <name>::::<url> ]; )
+QStringList LOS::RSSFeeds(){
+ QStringList feeds;
+ feeds << "DragonFly BSD Feed::::http://www.dragonflybsd.org/recentchanges/index.rss";
+ return feeds;
+}
// ==== ExternalDevicePaths() ====
QStringList LOS::ExternalDevicePaths(){
diff --git a/src-qt5/core/libLumina/LuminaOS-FreeBSD.cpp b/src-qt5/core/libLumina/LuminaOS-FreeBSD.cpp
index fb405cb5..6f03767b 100644
--- a/src-qt5/core/libLumina/LuminaOS-FreeBSD.cpp
+++ b/src-qt5/core/libLumina/LuminaOS-FreeBSD.cpp
@@ -26,6 +26,13 @@ QString LOS::SysPrefix(){ return "/usr/"; } //Prefix for system
//OS-specific application shortcuts (*.desktop files)
QString LOS::ControlPanelShortcut(){ return "/usr/local/share/applications/pccontrol.desktop"; } //system control panel
QString LOS::AppStoreShortcut(){ return "/usr/local/share/applications/appcafe.desktop"; } //graphical app/pkg manager
+//OS-specific RSS feeds (Format: QStringList[ <name>::::<url> ]; )
+QStringList LOS::RSSFeeds(){
+ QStringList feeds;
+ feeds << "FreeBSD News Feed::::https://www.freebsd.org/news/rss.xml";
+ feeds << "PC-BSD News Feed::::https://blog.pcbsd.org/?feed=rss2";
+ return feeds;
+ }
// ==== ExternalDevicePaths() ====
QStringList LOS::ExternalDevicePaths(){
diff --git a/src-qt5/core/libLumina/LuminaOS-Gentoo.cpp b/src-qt5/core/libLumina/LuminaOS-Gentoo.cpp
index e3d5fe56..3a9c7320 100644
--- a/src-qt5/core/libLumina/LuminaOS-Gentoo.cpp
+++ b/src-qt5/core/libLumina/LuminaOS-Gentoo.cpp
@@ -24,6 +24,8 @@ QString LOS::SysPrefix(){ return "/"; } //Prefix for system
//OS-specific application shortcuts (*.desktop files)
QString LOS::ControlPanelShortcut(){ return ""; } //system control panel
QString LOS::AppStoreShortcut(){ return LOS::AppPrefix() + "/share/applications/porthole.desktop"; } //graphical app/pkg manager
+//OS-specific RSS feeds (Format: QStringList[ <name>::::<url> ]; )
+QStringList LOS::RSSFeeds(){ return QStringList(); }
// ==== ExternalDevicePaths() ====
QStringList LOS::ExternalDevicePaths(){
diff --git a/src-qt5/core/libLumina/LuminaOS-Linux.cpp b/src-qt5/core/libLumina/LuminaOS-Linux.cpp
index 5939c9d1..c40cbd60 100644
--- a/src-qt5/core/libLumina/LuminaOS-Linux.cpp
+++ b/src-qt5/core/libLumina/LuminaOS-Linux.cpp
@@ -24,6 +24,8 @@ QString LOS::SysPrefix(){ return "/usr/"; } //Prefix for system
//OS-specific application shortcuts (*.desktop files)
QString LOS::ControlPanelShortcut(){ return ""; } //system control panel
QString LOS::AppStoreShortcut(){ return ""; } //graphical app/pkg manager
+//OS-specific RSS feeds (Format: QStringList[ <name>::::<url> ]; )
+QStringList LOS::RSSFeeds(){ return QStringList(); }
// ==== ExternalDevicePaths() ====
QStringList LOS::ExternalDevicePaths(){
diff --git a/src-qt5/core/libLumina/LuminaOS-NetBSD.cpp b/src-qt5/core/libLumina/LuminaOS-NetBSD.cpp
index 866ccc5c..e1152527 100644
--- a/src-qt5/core/libLumina/LuminaOS-NetBSD.cpp
+++ b/src-qt5/core/libLumina/LuminaOS-NetBSD.cpp
@@ -20,7 +20,13 @@ QString LOS::SysPrefix(){ return "/usr/"; } //Prefix for system
//OS-specific application shortcuts (*.desktop files)
QString LOS::ControlPanelShortcut(){ return ""; } //system control panel
QString LOS::AppStoreShortcut(){ return ""; } //graphical app/pkg manager
-
+//OS-specific RSS feeds (Format: QStringList[ <name>::::<url> ]; )
+QStringList LOS::RSSFeeds(){
+ QStringList feeds;
+ feeds << "NetBSD News::::http://www.netbsd.org/changes/rss-netbsd.xml";
+ return feeds;
+}
+
// ==== ExternalDevicePaths() ====
QStringList LOS::ExternalDevicePaths(){
//Returns: QStringList[<type>::::<filesystem>::::<path>]
diff --git a/src-qt5/core/libLumina/LuminaOS-OpenBSD.cpp b/src-qt5/core/libLumina/LuminaOS-OpenBSD.cpp
index c0fdafd4..30a02078 100644
--- a/src-qt5/core/libLumina/LuminaOS-OpenBSD.cpp
+++ b/src-qt5/core/libLumina/LuminaOS-OpenBSD.cpp
@@ -23,6 +23,8 @@ QString LOS::SysPrefix(){ return "/usr/"; } //Prefix for system
//OS-specific application shortcuts (*.desktop files)
QString LOS::ControlPanelShortcut(){ return ""; } //system control panel
QString LOS::AppStoreShortcut(){ return ""; } //graphical app/pkg manager
+//OS-specific RSS feeds (Format: QStringList[ <name>::::<url> ]; )
+QStringList LOS::RSSFeeds(){ return QStringList(); }
// ==== ExternalDevicePaths() ====
QStringList LOS::ExternalDevicePaths(){
diff --git a/src-qt5/core/libLumina/LuminaOS-kFreeBSD.cpp b/src-qt5/core/libLumina/LuminaOS-kFreeBSD.cpp
index 4fe62686..8414db1a 100644
--- a/src-qt5/core/libLumina/LuminaOS-kFreeBSD.cpp
+++ b/src-qt5/core/libLumina/LuminaOS-kFreeBSD.cpp
@@ -28,6 +28,8 @@ QString LOS::SysPrefix(){ return "/usr/"; } //Prefix for system
//OS-specific application shortcuts (*.desktop files)
QString LOS::ControlPanelShortcut(){ return ""; } //system control panel
QString LOS::AppStoreShortcut(){ return ""; } //graphical app/pkg manager
+//OS-specific RSS feeds (Format: QStringList[ <name>::::<url> ]; )
+QStringList LOS::RSSFeeds(){ return QStringList(); }
// ==== ExternalDevicePaths() ====
QStringList LOS::ExternalDevicePaths(){
diff --git a/src-qt5/core/libLumina/LuminaOS-template.cpp b/src-qt5/core/libLumina/LuminaOS-template.cpp
index 5969bf3a..7aea0edd 100644
--- a/src-qt5/core/libLumina/LuminaOS-template.cpp
+++ b/src-qt5/core/libLumina/LuminaOS-template.cpp
@@ -20,7 +20,9 @@ QString LOS::SysPrefix(){ return "/usr/"; } //Prefix for system
//OS-specific application shortcuts (*.desktop files)
QString LOS::ControlPanelShortcut(){ return ""; } //system control panel
QString LOS::AppStoreShortcut(){ return ""; } //graphical app/pkg manager
-
+//OS-specific RSS feeds (Format: QStringList[ <name>::::<url> ]; )
+QStringList LOS::RSSFeeds(){ return QStringList(); }
+
// ==== ExternalDevicePaths() ====
QStringList LOS::ExternalDevicePaths(){
//Returns: QStringList[<type>::::<filesystem>::::<path>]
diff --git a/src-qt5/core/libLumina/LuminaOS.h b/src-qt5/core/libLumina/LuminaOS.h
index c305277a..a18f2909 100644
--- a/src-qt5/core/libLumina/LuminaOS.h
+++ b/src-qt5/core/libLumina/LuminaOS.h
@@ -34,6 +34,9 @@ public:
static QString ControlPanelShortcut();
static QString AppStoreShortcut();
+ //OS-specific RSS feeds
+ static QStringList RSSFeeds(); //Return Format: QStringList[ <name>::::<url> ];
+
//Scan for mounted external devices
static QStringList ExternalDevicePaths(); //Returns: QStringList[<type>::::<filesystem>::::<path>]
//Note: <type> = [USB, HDRIVE, DVD, SDCARD, UNKNOWN]
diff --git a/src-qt5/core/libLumina/LuminaUtils.cpp b/src-qt5/core/libLumina/LuminaUtils.cpp
index 12dcf0be..4911b9fa 100644
--- a/src-qt5/core/libLumina/LuminaUtils.cpp
+++ b/src-qt5/core/libLumina/LuminaUtils.cpp
@@ -211,6 +211,23 @@ QString LUtils::PathToAbsolute(QString path){
}
return path;
}
+QString LUtils::AppToAbsolute(QString path){
+ if(path.startsWith("/") || QFile::exists(path)){ return path; }
+ if(path.endsWith(".desktop")){
+ //Look in the XDG dirs
+ QStringList dirs = LXDG::systemApplicationDirs();
+ for(int i=0; i<dirs.length(); i++){
+ if(QFile::exists(dirs[i]+"/"+path)){ return (dirs[i]+"/"+path); }
+ }
+ }else{
+ //Look on $PATH for the binary
+ QStringList paths = QString(getenv("PATH")).split(":");
+ for(int i=0; i<paths.length(); i++){
+ if(QFile::exists(paths[i]+"/"+path)){ return (paths[i]+"/"+path); }
+ }
+ }
+ return path;
+}
QStringList LUtils::imageExtensions(bool wildcards){
//Note that all the image extensions are lowercase!!
@@ -472,6 +489,7 @@ QStringList LUtils::listFavorites(){
if(lastRead.isNull() || lastRead<QFileInfo(QDir::homePath()+"/.lumina/favorites/fav.list").lastModified()){
fav = LUtils::readFile(QDir::homePath()+"/.lumina/favorites/fav.list");
fav.removeAll(""); //remove any empty lines
+ fav.removeDuplicates();
lastRead = cur;
if(fav.isEmpty()){
//Make sure the favorites dir exists, and create it if necessary
@@ -484,6 +502,7 @@ QStringList LUtils::listFavorites(){
}
bool LUtils::saveFavorites(QStringList list){
+ list.removeDuplicates();
bool ok = LUtils::writeFile(QDir::homePath()+"/.lumina/favorites/fav.list", list, true);
if(ok){ fav = list; } //also save internally in case of rapid write/read of the file
return ok;
@@ -576,7 +595,7 @@ void LUtils::LoadSystemDefaults(bool skipOS){
}
}
//Now setup the default "desktopsettings.conf" and "sessionsettings.conf" files
- QStringList deskset, sesset, lopenset;
+ QStringList deskset, sesset;//, lopenset;
// -- SESSION SETTINGS --
QStringList tmp = sysDefaults.filter("session_");
@@ -593,38 +612,71 @@ void LUtils::LoadSystemDefaults(bool skipOS){
if(var.contains(".")){ var.replace(".","_"); }
//Now parse the variable and put the value in the proper file
+ if(var.contains("_default_")){ val = AppToAbsolute(val); } //got an application/binary
//Special handling for values which need to exist first
if(var.endsWith("_ifexists") ){
var = var.remove("_ifexists"); //remove this flag from the variable
//Check if the value exists (absolute path only)
if(!QFile::exists(val)){ continue; } //skip this line - value/file does not exist
}
+
//Parse/save the value
- QString loset, sset; //temporary strings
+ QString sset; //temporary strings
if(var=="session_enablenumlock"){ sset = "EnableNumlock="+ istrue; }
else if(var=="session_playloginaudio"){ sset = "PlayStartupAudio="+istrue; }
else if(var=="session_playlogoutaudio"){ sset = "PlayLogoutAudio="+istrue; }
- else if(var=="session_default_terminal"){ sset = "default-terminal="+val; }
- else if(var=="session_default_filemanager"){
- sset = "default-filemanager="+val;
- loset = "directory="+val;
+ else if(var=="session_default_terminal"){
+ LXDG::setDefaultAppForMime("application/terminal", val);
+ //sset = "default-terminal="+val;
+ }else if(var=="session_default_filemanager"){
+ LXDG::setDefaultAppForMime("inode/directory", val);
+ //sset = "default-filemanager="+val;
+ //loset = "directory="+val;
+ }else if(var=="session_default_webbrowser"){
+ //loset = "webbrowser="+val;
+ LXDG::setDefaultAppForMime("x-scheme-handler/http", val);
+ LXDG::setDefaultAppForMime("x-scheme-handler/https", val);
+ }else if(var=="session_default_email"){
+ LXDG::setDefaultAppForMime("application/email",val);
+ //loset = "email="+val;
}
- else if(var=="session_default_webbrowser"){ loset = "webbrowser="+val; }
- else if(var=="session_default_email"){ loset = "email="+val; }
//Put the line into the file (overwriting any previous assignment as necessary)
- if(!loset.isEmpty()){
+ /*if(!loset.isEmpty()){
int index = lopenset.indexOf(QRegExp(loset.section("=",0,0)+"=*", Qt::CaseSensitive, QRegExp::Wildcard));
qDebug() << "loset line:" << loset << index << lopenset;
if(index<0){ lopenset << loset; } //new line
else{ lopenset[index] = loset; } //overwrite the other line
- }
+ }*/
if(!sset.isEmpty()){
int index = sesset.indexOf(QRegExp(sset.section("=",0,0)+"=*", Qt::CaseSensitive, QRegExp::Wildcard));
if(index<0){ sesset << sset; } //new line
else{ sesset[index] = sset; } //overwrite the other line
}
}
- if(!lopenset.isEmpty()){ lopenset.prepend("[default]"); } //the session options exist within this set
+ //if(!lopenset.isEmpty()){ lopenset.prepend("[default]"); } //the session options exist within this set
+
+ // -- MIMETYPE DEFAULTS --
+ tmp = sysDefaults.filter("mime_default_");
+ for(int i=0; i<tmp.length(); i++){
+ if(tmp[i].startsWith("#") || !tmp[i].contains("=") ){ continue; }
+ QString var = tmp[i].section("=",0,0).toLower().simplified();
+ QString val = tmp[i].section("=",1,1).section("#",0,0).simplified();
+ if(val.isEmpty()){ continue; }
+ QString istrue = (val.toLower()=="true") ? "true": "false";
+ //Change in 0.8.5 - use "_" instead of "." within variables names - need backwards compat for a little while
+ if(var.contains(".")){ var.replace(".","_"); }
+ //Now parse the variable and put the value in the proper file
+ val = AppToAbsolute(val);
+ //Special handling for values which need to exist first
+ if(var.endsWith("_ifexists") ){
+ var = var.remove("_ifexists"); //remove this flag from the variable
+ //Check if the value exists (absolute path only)
+ if(!QFile::exists(val)){ continue; } //skip this line - value/file does not exist
+ }
+ //Now turn this variable into the mimetype only
+ var = var.section("_default_",1,-1);
+ LXDG::setDefaultAppForMime(var, val);
+ }
// -- DESKTOP SETTINGS --
//(only works for the primary desktop at the moment)
@@ -710,6 +762,7 @@ void LUtils::LoadSystemDefaults(bool skipOS){
if(var.contains(".")){ var.replace(".","_"); }
//Now parse the variable and put the value in the proper file
qDebug() << "Favorite entry:" << var << val;
+ val = AppToAbsolute(val); //turn any relative files into absolute
if(var=="favorites_add_ifexists" && QFile::exists(val)){ qDebug() << " - Exists/Adding:"; LUtils::addFavorite(val); }
else if(var=="favorites_add"){ qDebug() << " - Adding:"; LUtils::addFavorite(val); }
else if(var=="favorites_remove"){ qDebug() << " - Removing:"; LUtils::removeFavorite(val); }
@@ -780,7 +833,7 @@ void LUtils::LoadSystemDefaults(bool skipOS){
if(setTheme){ LTHEME::setCurrentSettings( themesettings[0], themesettings[1], themesettings[2], themesettings[3], themesettings[4]); }
LUtils::writeFile(setdir+"/sessionsettings.conf", sesset, true);
LUtils::writeFile(setdir+"/desktopsettings.conf", deskset, true);
- LUtils::writeFile(setdir+"/lumina-open.conf", lopenset, true);
+ //LUtils::writeFile(setdir+"/lumina-open.conf", lopenset, true);
}
bool LUtils::checkUserFiles(QString lastversion){
diff --git a/src-qt5/core/libLumina/LuminaUtils.h b/src-qt5/core/libLumina/LuminaUtils.h
index 32109244..e07363ca 100644
--- a/src-qt5/core/libLumina/LuminaUtils.h
+++ b/src-qt5/core/libLumina/LuminaUtils.h
@@ -54,8 +54,9 @@ public:
static QStringList listSubDirectories(QString dir, bool recursive = true);
//Convert an input file/dir path to an absolute file path
- static QString PathToAbsolute(QString path);
-
+ static QString PathToAbsolute(QString path); //This is primarily for CLI usage (relative paths)
+ static QString AppToAbsolute(QString path); //This is for looking up a binary/ *.desktop path
+
//Get the list of all file extensions which Qt can read (lowercase)
static QStringList imageExtensions(bool wildcards = false);
diff --git a/src-qt5/core/libLumina/LuminaX11.h b/src-qt5/core/libLumina/LuminaX11.h
index b0a5d588..b7310abd 100644
--- a/src-qt5/core/libLumina/LuminaX11.h
+++ b/src-qt5/core/libLumina/LuminaX11.h
@@ -69,6 +69,14 @@ public:
}
};
+//simple data structure for passing around the XRANDR information
+/*class monitor_info{
+public:
+ QString ID;
+ bool active;
+ QRect geometry;
+};*/
+
//XCB Library replacement for LX11 (Qt5 uses XCB instead of XLib)
class LXCB{
@@ -393,6 +401,12 @@ public:
WId WM_Get_CM_Owner();
void WM_Set_CM_Owner(WId win);
+ //============
+ // RANDR Functions (directly reading changing monitor outputs)
+ //============
+ //QList<monitor_info> RR_List_Monitors();
+ //void RR_Set_Monitors(QList<monitor_info> monitors);
+
private:
QList<xcb_atom_t> ATOMS;
QStringList atoms;
diff --git a/src-qt5/core/libLumina/LuminaXDG.cpp b/src-qt5/core/libLumina/LuminaXDG.cpp
index bfca4f71..8f6ada37 100644
--- a/src-qt5/core/libLumina/LuminaXDG.cpp
+++ b/src-qt5/core/libLumina/LuminaXDG.cpp
@@ -854,20 +854,27 @@ QString LXDG::findDefaultAppForMime(QString mime){
//Now go through all the files in order of priority until a default is found
QString cdefault;
- QStringList white; //lists to keep track of during the search (black unused at the moment)
for(int i=0; i<dirs.length() && cdefault.isEmpty(); i++){
if(!QFile::exists(dirs[i])){ continue; }
QStringList info = LUtils::readFile(dirs[i]);
if(info.isEmpty()){ continue; }
- QString workdir = dirs[i].section("/",0,-1); //just the directory
+ QStringList white; //lists to keep track of during the search (black unused at the moment)
+ QString workdir = dirs[i].section("/",0,-2); //just the directory
+ // qDebug() << "Check File:" << mime << dirs[i] << workdir;
int def = info.indexOf("[Default Applications]"); //find this line to start on
if(def>=0){
for(int d=def+1; d<info.length(); d++){
+ //qDebug() << "Check Line:" << info[d];
if(info[d].startsWith("[")){ break; } //starting a new section now - finished with defaults
- if(info[d].contains(mime+"=")){
- white << info[d].section("=",1,50).split(";");
- break;
- }
+ if(info[d].contains(mime+"=") ){
+ white = info[d].section("=",1,-1).split(";") + white; //exact mime match - put at front of list
+ break; //already found exact match
+ }else if(info[d].contains("*") && info[d].contains("=") ){
+ QRegExp rg(info[d].section("=",0,0), Qt::CaseSensitive, QRegExp::WildcardUnix);
+ if(rg.exactMatch(mime)){
+ white << info[d].section("=",1,-1).split(";"); //partial mime match - put at end of list
+ }
+ }
}
}
// Now check for any white-listed files in this work dir
@@ -884,19 +891,10 @@ QString LXDG::findDefaultAppForMime(QString mime){
else if( QFile::exists(workdir+"/"+white[w]) ){ cdefault=workdir+"/"+white[w]; break; }
//Now go through the XDG DATA dirs and see if the file is in there
else{
- QStringList xdirs;
- xdirs << QString(getenv("XDG_DATA_HOME"))+"/applications/";
- tmp = QString(getenv("XDG_DATA_DIRS")).split(":");
- for(int t=0; t<tmp.length(); t++){ xdirs << tmp[t]+"/applications/"; }
- //Now scan these dirs
- bool found = false;
- //qDebug() << "Scan dirs:" << white[w] << xdirs;
- for(int x=0; x<xdirs.length() && !found; x++){
- if(QFile::exists(xdirs[x]+white[w])){cdefault=xdirs[x]+white[w]; found = true; }
- }
- if(found){ break; }
+ white[w] = LUtils::AppToAbsolute(white[w]);
+ if(QFile::exists(white[w])){ cdefault = white[w]; }
}
- }
+ }
/* WRITTEN BUT UNUSED CODE FOR MIMETYPE ASSOCIATIONS
//Skip using this because it is simply an alternate/unsupported standard that conflicts with
the current mimetype database standards. It is better/faster to parse 1 or 2 database glob files
diff --git a/src-qt5/core/lumina-desktop/AppMenu.cpp b/src-qt5/core/lumina-desktop/AppMenu.cpp
index 14af988a..0b8aeace 100644
--- a/src-qt5/core/lumina-desktop/AppMenu.cpp
+++ b/src-qt5/core/lumina-desktop/AppMenu.cpp
@@ -32,6 +32,7 @@ QHash<QString, QList<XDGDesktop> >* AppMenu::currentAppHash(){
// PRIVATE
//===========
void AppMenu::updateAppList(){
+ watcher->removePaths(watcher->directories());
//Make sure the title/icon are updated as well (in case of locale/icon change)
this->setTitle(tr("Applications"));
this->setIcon( LXDG::findIcon("system-run","") );
@@ -111,6 +112,7 @@ void AppMenu::updateAppList(){
}
this->addMenu(menu);
}
+ watcher->addPaths(LXDG::systemApplicationDirs());
emit AppMenuUpdated();
}
diff --git a/src-qt5/core/lumina-desktop/LDesktop.cpp b/src-qt5/core/lumina-desktop/LDesktop.cpp
index 113b7efc..11d99581 100644
--- a/src-qt5/core/lumina-desktop/LDesktop.cpp
+++ b/src-qt5/core/lumina-desktop/LDesktop.cpp
@@ -104,7 +104,7 @@ void LDesktop::SystemLogout(){
void LDesktop::SystemTerminal(){
LSession::handle()->sessionSettings()->sync(); //make sure it is up to date
- QString term = LSession::handle()->sessionSettings()->value("default-terminal","xterm").toString();
+ QString term = LXDG::findDefaultAppForMime("application/terminal"); //LSession::handle()->sessionSettings()->value("default-terminal","xterm").toString();
if(term.endsWith(".desktop")){ term = "lumina-open \""+term+"\""; }
LSession::LaunchApplication(term);
}
diff --git a/src-qt5/core/lumina-desktop/LWinInfo.cpp b/src-qt5/core/lumina-desktop/LWinInfo.cpp
index 3ff0c2d7..6a6cea0b 100644
--- a/src-qt5/core/lumina-desktop/LWinInfo.cpp
+++ b/src-qt5/core/lumina-desktop/LWinInfo.cpp
@@ -21,7 +21,7 @@ QString LWinInfo::text(){
if(nm.simplified().isEmpty()){ nm = LSession::handle()->XCB->OldWindowIconName(window); }
if(nm.simplified().isEmpty()){ nm = LSession::handle()->XCB->OldWindowName(window); }
//Make sure that the text is a reasonable size (40 char limit)
- if(nm.length()>40){ nm = nm.left(40)+"..."; }
+ //if(nm.length()>40){ nm = nm.left(40)+"..."; }
return nm;
}
@@ -45,4 +45,4 @@ LXCB::WINDOWVISIBILITY LWinInfo::status(bool update){
cstate = LSession::handle()->XCB->WindowState(window);
}
return cstate;
-} \ No newline at end of file
+}
diff --git a/src-qt5/core/lumina-desktop/defaults/luminaDesktop.conf b/src-qt5/core/lumina-desktop/defaults/luminaDesktop.conf
index 2c973adb..251e8309 100644
--- a/src-qt5/core/lumina-desktop/defaults/luminaDesktop.conf
+++ b/src-qt5/core/lumina-desktop/defaults/luminaDesktop.conf
@@ -6,12 +6,12 @@
# system corresponding to the XDG mime-type specifications for default applications
# See Here for specifications: http://www.freedesktop.org/wiki/Specifications/mime-apps-spec/
-# Possible Desktop Plugins (Lumina version 0.8.7):
-# calendar, applauncher[::absolute path to *.desktop file], desktopview, notepad, audioplayer
-# Possible Panel Plugins (Lumina version 0.8.7):
+# Possible Desktop Plugins (Lumina version 0.9.1):
+# calendar, applauncher[::absolute path to *.desktop file], desktopview, notepad, audioplayer, rssreader
+# Possible Panel Plugins (Lumina version 0.9.1):
# userbutton, desktopbar, spacer, desktopswitcher, battery, clock, systemdashboard, systemstart
# taskmanager[-nogroups], systemtray, homebutton, appmenu, applauncher[::absolute path to *.desktop file]
-# Possible Menu Plugins (Lumina version 0.8.7):
+# Possible Menu Plugins (Lumina version 0.9.1):
# terminal, filemanager, applications, line, settings, windowlist, app::<absolute path to *.desktop file>
#GENERAL SESSION SETTINGS
@@ -22,32 +22,50 @@ session_playlogoutaudio=true #[true/false] Play the audio chimes on log out
# DEFAULT UTILITIES
# Provide the full path to *.desktop file, or a binary name which exists on PATH
# *.desktop files provide better support for input formats, and are recommended
-#session_default_terminal=xterm
-#session_default_filemanager=lumina-fm
-#session_default_webbrowser=/usr/local/share/applications/firefox.desktop
-#session_default_email=/usr/local/share/applications/thunderbird.desktop
+#Note: the last "ifexists" entry has the highest priority for each session utility
+session_default_terminal_ifexists=xterm.desktop
+session_default_terminal_ifexists=lumina-terminal.desktop
+session_default_filemanager=lumina-fm.desktop
+session_default_webbrowser_ifexists=chromium-browser.desktop
+session_default_webbrowser_ifexists=firefox.desktop
+session_default_webbrowser_ifexists=qupzilla.desktop
+session_default_email_ifexists=trojita.desktop
+
+#DEFAULT UTILITIES FOR INDIVIDUAL MIME TYPES
+# Format: mime_default_<mimetype>[_ifexists]=<*.desktop file>
+mime_default_text/*_ifexists=lumina-textedit.desktop
+mime_default_audio/*_ifexists=vlc.desktop
+mime_default_video/*_ifexists=vlc.desktop
+mime_default_application/zip_ifexists=peazip.desktop
+mime_default_application/x-compressed-tar_ifexists=peazip.desktop
+mime_default_application/x-bzip-compressed-tar_ifexists=peazip.desktop
+mime_default_application/x-lrzip-compressed-tar_ifexists=peazip.desktop
+mime_default_application/x-lzma-compressed-tar_ifexists=peazip.desktop
+mime_default_application/x-xz-compressed-tar_ifexists=peazip.desktop
+mime_default_application/x-tar_ifexists=peazip.desktop
+
#THEME SETTINGS
-#theme.themefile=<file path> #Absolute path to the theme template file to use (disable for Lumina-Default)
+theme_themefile=Glass #Name of the theme to use (disable for Lumina-Default)
theme_colorfile=Black #Name of the color spec file to use for theming
theme_iconset=oxygen #Name of the icon theme to use
theme_font=Arial #Name of the font family to use
theme_fontsize=10pt #Default size of the fonts to use on the desktop (can also use a percentage of the screen height (<number>%) )
#DESKTOP SETTINGS (used for the primary screen in multi-screen setups)
-desktop_visiblepanels=1 #[0/1/2] The number of panels visible by default
+desktop_visiblepanels=1 #[0 - 12] The number of panels visible by default
#desktop.backgroundfiles= #list of absolute file paths for image files (disable for Lumina default)
desktop_backgroundrotateminutes=5 #[positive integer] number of minutes between background rotations (if multiple files)
-desktop_plugins= #list of plugins to be shown on the desktop by default
+desktop_plugins=rssreader #list of plugins to be shown on the desktop by default
desktop_generate_icons=true #[true/false] Auto-generate launchers for ~/Desktop items
#PANEL SETTINGS (preface with panel1.<setting> or panel2.<setting>, depending on the number of panels you have visible by default)
-panel1_location=top #[top/bottom/left/right] Screen edge the panel should be on
+panel1_location=bottom #[top/bottom/left/right] Screen edge the panel should be on
panel1_pixelsize=4%H #number of pixels wide/high the panel should be (or <number>%[W/H] for a percentage of the screen width/height)
panel1_autohide=false #[true/false] Have the panel become visible on mouse-over
panel1_plugins=systemstart, taskmanager-nogroups, spacer, systemtray, clock #list of plugins for the panel
panel1_pinlocation=center #[left/center/right] Note:[left/right] corresponds to [top/bottom] for vertical panels
-panel1_edgepercent=90 #[1->100] percentage of the screen edge to use
+panel1_edgepercent=99 #[1->100] percentage of the screen edge to use
#MENU SETTINGS (right-click menu)
menu_plugins=terminal, filemanager, applications, line, settings #list of menu plugins to show
@@ -56,3 +74,11 @@ menu_plugins=terminal, filemanager, applications, line, settings #list of menu p
#favorites_add=<file/dir path> #Create a favorites entry for this file/dir
#favorites_remove=<file/dir path> #Remove a favorites entry for this file/dir
#favorites_add_ifexists=<file/dir path> #Create a favorites entry for this file/dir if the file/dir exists
+favorites_add_ifexists=firefox.desktop
+favorites_add_ifexists=chromium-browser.desktop
+favorites_add_ifexists=qupzilla.desktop
+favorites_add_ifexists=thunderbird.desktop
+favorites_add_ifexists=trojita.desktop
+favorites_add_ifexists=smplayer.desktop
+favorites_add_ifexists=vlc.desktop
+favorites_add_ifexists=pithos.desktop
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/NewDP.h b/src-qt5/core/lumina-desktop/desktop-plugins/NewDP.h
index a12341bb..e28b8c61 100644
--- a/src-qt5/core/lumina-desktop/desktop-plugins/NewDP.h
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/NewDP.h
@@ -22,6 +22,7 @@
#include "systemmonitor/MonitorWidget.h"
//#include "quickcontainer/QuickDPlugin.h"
//#include "messagecenter/MessageCenter.h"
+#include "rssreader/RSSFeedPlugin.h"
class NewDP{
public:
@@ -48,6 +49,8 @@ public:
//plug = new MessageCenterPlugin(parent, plugin);
//}else if(plugin.section("---",0,0).startsWith("quick-") && LUtils::validQuickPlugin(plugin.section("---",0,0)) ){
//plug = new QuickDPlugin(parent, plugin);
+ }else if(plugin.section("---",0,0)=="rssreader"){
+ plug = new RSSFeedPlugin(parent, plugin);
}else{
qWarning() << "Invalid Desktop Plugin:"<<plugin << " -- Ignored";
}
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/calendar/CalendarPlugin.h b/src-qt5/core/lumina-desktop/desktop-plugins/calendar/CalendarPlugin.h
index b3a6a8d7..abb138f7 100644
--- a/src-qt5/core/lumina-desktop/desktop-plugins/calendar/CalendarPlugin.h
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/calendar/CalendarPlugin.h
@@ -31,6 +31,7 @@ public:
timer = new QTimer(this);
timer->setInterval(1800000); //30 minute refresh timer
timer->start();
+ connect(timer, SIGNAL(timeout()), this, SLOT(updateDate()) );
QTimer::singleShot(0,this, SLOT(updateDate()) );
connect(this, SIGNAL(PluginResized()), this, SLOT(UpdateCalendarSize()));
}
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/desktop-plugins.pri b/src-qt5/core/lumina-desktop/desktop-plugins/desktop-plugins.pri
index 5a631b52..8376316a 100644
--- a/src-qt5/core/lumina-desktop/desktop-plugins/desktop-plugins.pri
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/desktop-plugins.pri
@@ -2,7 +2,9 @@ SOURCES += $$PWD/applauncher/AppLauncherPlugin.cpp \
$$PWD/desktopview/DesktopViewPlugin.cpp \
$$PWD/notepad/NotepadPlugin.cpp \
$$PWD/audioplayer/PlayerWidget.cpp \
- $$PWD/systemmonitor/MonitorWidget.cpp
+ $$PWD/systemmonitor/MonitorWidget.cpp \
+ $$PWD/rssreader/RSSFeedPlugin.cpp \
+ $$PWD/rssreader/RSSObjects.cpp
# $$PWD/messagecenter/MessageCenter.cpp
HEADERS += $$PWD/calendar/CalendarPlugin.h \
@@ -11,9 +13,12 @@ HEADERS += $$PWD/calendar/CalendarPlugin.h \
$$PWD/desktopview/DesktopViewPlugin.h \
$$PWD/notepad/NotepadPlugin.h \
$$PWD/audioplayer/PlayerWidget.h \
- $$PWD/systemmonitor/MonitorWidget.h
+ $$PWD/systemmonitor/MonitorWidget.h \
+ $$PWD/rssreader/RSSFeedPlugin.h \
+ $$PWD/rssreader/RSSObjects.h
# $$PWD/quickcontainer/QuickDPlugin.h
# $$PWD/messagecenter/MessageCenter.h
FORMS += $$PWD/audioplayer/PlayerWidget.ui \
- $$PWD/systemmonitor/MonitorWidget.ui \ No newline at end of file
+ $$PWD/systemmonitor/MonitorWidget.ui \
+ $$PWD/rssreader/RSSFeedPlugin.ui
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSFeedPlugin.cpp b/src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSFeedPlugin.cpp
new file mode 100644
index 00000000..23c1ca01
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSFeedPlugin.cpp
@@ -0,0 +1,363 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2016, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "RSSFeedPlugin.h"
+#include "ui_RSSFeedPlugin.h"
+
+#include <LuminaXDG.h>
+#include "LSession.h"
+#include <LuminaUtils.h>
+#include <QDir>
+#include <QFileDialog>
+#include <QInputDialog>
+#include <QtConcurrent>
+
+RSSFeedPlugin::RSSFeedPlugin(QWidget* parent, QString ID) : LDPlugin(parent, ID), ui(new Ui::RSSFeedPlugin()){
+ ui->setupUi(this);
+ //Load the global settings
+ setprefix = "rssreader/"; //this structure/prefix should be used for *all* plugins of this type
+ RSS = new RSSReader(this, setprefix);
+
+ //Create the options menu
+ optionsMenu = new QMenu(this);
+ ui->tool_options->setMenu(optionsMenu);
+ presetMenu = new QMenu(this);
+ ui->tool_add_preset->setMenu(presetMenu);
+
+ //Setup any signal/slot connections
+ connect(ui->push_back1, SIGNAL(clicked()), this, SLOT(backToFeeds()) );
+ connect(ui->push_back2, SIGNAL(clicked()), this, SLOT(backToFeeds()) );
+ connect(ui->push_back3, SIGNAL(clicked()), this, SLOT(backToFeeds()) );
+ connect(ui->push_save_settings, SIGNAL(clicked()), this, SLOT(saveSettings()) );
+ connect(RSS, SIGNAL(rssChanged(QString)), this, SLOT(RSSItemChanged(QString)) );
+ connect(RSS, SIGNAL(newChannelsAvailable()), this, SLOT(UpdateFeedList()));
+ connect(ui->tool_gotosite, SIGNAL(clicked()), this, SLOT(openFeedPage()) );
+ connect(ui->push_rm_feed, SIGNAL(clicked()), this, SLOT(removeFeed()) );
+ connect(ui->push_add_url, SIGNAL(clicked()), this, SLOT(addNewFeed()) );
+ connect(ui->combo_feed, SIGNAL(currentIndexChanged(int)), this, SLOT(currentFeedChanged()) );
+
+ connect(presetMenu, SIGNAL(triggered(QAction*)), this, SLOT(loadPreset(QAction*)) );
+
+ updateOptionsMenu();
+ QTimer::singleShot(0,this, SLOT(ThemeChange()) );
+ //qDebug() << " - Done with init";
+ QStringList feeds;
+ if( !LSession::handle()->DesktopPluginSettings()->contains(setprefix+"currentfeeds") ){
+ //First-time run of the plugin - automatically load the default feeds
+ feeds = LOS::RSSFeeds();
+ for(int i=0; i<feeds.length(); i++){ feeds[i] = feeds[i].section("::::",1,-1); } //just need url right now
+ feeds << "http://lumina-desktop.org/?feed=rss2"; //Lumina Desktop blog feed
+ LSession::handle()->DesktopPluginSettings()->setValue(setprefix+"currentfeeds", feeds);
+ }else{
+ feeds = LSession::handle()->DesktopPluginSettings()->value(setprefix+"currentfeeds",QStringList()).toStringList();
+ }
+ RSS->addUrls(feeds);
+ backToFeeds(); //always load the first page
+}
+
+RSSFeedPlugin::~RSSFeedPlugin(){
+
+}
+
+//================
+// PRIVATE
+//================
+void RSSFeedPlugin::updateOptionsMenu(){
+ optionsMenu->clear();
+ optionsMenu->addAction(LXDG::findIcon("list-add",""), tr("Add RSS Feed"), this, SLOT(openFeedNew()) );
+ optionsMenu->addAction(LXDG::findIcon("help-about",""), tr("View Feed Details"), this, SLOT(openFeedInfo()) );
+ optionsMenu->addAction(LXDG::findIcon("configure",""), tr("Settings"), this, SLOT(openSettings()) );
+ optionsMenu->addSeparator();
+ optionsMenu->addAction(LXDG::findIcon("download",""), tr("Update Feeds Now"), this, SLOT(resyncFeeds()) );
+
+ presetMenu->clear();
+ QStringList feeds = LOS::RSSFeeds();
+ feeds << tr("Lumina Desktop RSS")+"::::http://lumina-desktop.org/?feed=rss2";
+ feeds.sort();
+ for(int i=0; i<feeds.length(); i++){
+ QAction *tmp = presetMenu->addAction(feeds[i].section("::::",0,0) );
+ tmp->setWhatsThis( feeds[i].section("::::",1,-1) );
+ }
+}
+
+void RSSFeedPlugin::checkFeedNotify(){
+ bool notify = false;
+ for(int i=0; i<ui->combo_feed->count() && !notify; i++){
+ if( !ui->combo_feed->itemData(i, Qt::WhatsThisRole).toString().isEmpty()){ notify = true; }
+ }
+ QString style;
+ if(notify){ style = "QComboBox{ background-color: rgba(255,0,0,120); }"; }
+ ui->combo_feed->setStyleSheet(style);
+}
+
+//Simplification functions for loading feed info onto widgets
+void RSSFeedPlugin::updateFeed(QString ID){
+ //Now clear/update the feed viewer (HTML)
+ ui->text_feed->clear();
+ if(ID.isEmpty()){ return; } //nothing to show
+
+ //Save the datetime this feed was read
+ LSession::handle()->DesktopPluginSettings()->setValue(setprefix+"feedReads/"+ID, QDateTime::currentDateTime() );
+ //Get the color to use for hyperlinks (need to specify in html)
+ QString color = ui->text_feed->palette().text().color().name(); //keep the hyperlinks the same color as the main text (different formatting still applies)
+ QString html;
+ RSSchannel data = RSS->dataForID(ID);
+ ui->label_lastupdate->setText( data.lastsync.toString(Qt::DefaultLocaleShortDate) );
+ // - generate the html
+ // html.append("<ul style=\"margin-left: 3px;\">\n");
+ for(int i=0; i<data.items.length(); i++){
+ //html.append("<li>");
+ html.append("<h4><a href=\""+data.items[i].link+"\" style=\"color: "+color+";\">"+data.items[i].title+"</a></h4>");
+ if(!data.items[i].pubdate.isNull() || !data.items[i].author.isEmpty()){
+ html.append("<i>(");
+ if(!data.items[i].pubdate.isNull()){ html.append(data.items[i].pubdate.toString(Qt::DefaultLocaleShortDate)); }
+ if(!data.items[i].author.isEmpty()){
+ if(!html.endsWith("(")){ html.append(", "); } //spacing between date/author
+ if(!data.items[i].author_email.isEmpty()){ html.append("<a href=\"mailto:"+data.items[i].author_email+"\" style=\"color: "+color+";\">"+data.items[i].author+"</a>"); }
+ else{ html.append(data.items[i].author); }
+ }
+ html.append(")</i><br>");
+ }
+ html.append(data.items[i].description);
+ //html.append("</li>\n");
+ if(i+1 < data.items.length()){ html.append("<br>"); }
+ }
+ //html.append("</ul>\n");
+ // - load that html into the viewer
+ ui->text_feed->setHtml(html);
+}
+
+void RSSFeedPlugin::updateFeedInfo(QString ID){
+ ui->page_feed_info->setWhatsThis(ID);
+ ui->text_feed_info->clear();
+ if(ID.isEmpty()){ return; }
+ //Get the color to use for hyperlinks (need to specify in html)
+ QString color = ui->text_feed->palette().text().color().name(); //keep the hyperlinks the same color as the main text (different formatting still applies)
+ QString html;
+ RSSchannel data = RSS->dataForID(ID);
+ // - generate the html
+ // <a href=\""+LINK+"\" style=\"color: "+color+";\">"+TEXT+"</a>
+ html.append( QString(tr("Feed URL: %1")).arg("<a href=\""+data.originalURL+"\" style=\"color: "+color+";\">"+data.originalURL+"</a>") +"<br><hr>");
+ html.append( QString(tr("Title: %1")).arg(data.title) +"<br>");
+ html.append( QString(tr("Description: %1")).arg(data.description) +"<br>");
+ html.append( QString(tr("Website: %1")).arg("<a href=\""+data.link+"\" style=\"color: "+color+";\">"+data.link+"</a>") +"<br><hr>");
+ if(!data.lastBuildDate.isNull()){ html.append( QString(tr("Last Build Date: %1")).arg(data.lastBuildDate.toString(Qt::DefaultLocaleShortDate)) +"<br>"); }
+ html.append( QString(tr("Last Sync: %1")).arg(data.lastsync.toString(Qt::DefaultLocaleShortDate)) +"<br>");
+ html.append( QString(tr("Next Sync: %1")).arg(data.nextsync.toString(Qt::DefaultLocaleShortDate)) +"<br>");
+ // - load that html into the viewer
+ ui->text_feed_info->setHtml(html);
+}
+
+//================
+// PRIVATE SLOTS
+//================
+void RSSFeedPlugin::loadIcons(){
+ ui->tool_options->setIcon( LXDG::findIcon("configure","") );
+ ui->tool_gotosite->setIcon( LXDG::findIcon("applications-internet","") );
+ ui->push_back1->setIcon( LXDG::findIcon("go-previous","") );
+ ui->push_back2->setIcon( LXDG::findIcon("go-previous","") );
+ ui->push_back3->setIcon( LXDG::findIcon("go-previous","") );
+ ui->push_rm_feed->setIcon( LXDG::findIcon("list-remove","") );
+ ui->push_add_url->setIcon( LXDG::findIcon("list-add","") );
+ ui->push_save_settings->setIcon( LXDG::findIcon("document-save","") );
+ ui->tool_add_preset->setIcon( LXDG::findIcon("bookmark-new-list","") );
+}
+
+//GUI slots
+// - Page management
+void RSSFeedPlugin::backToFeeds(){
+ ui->stackedWidget->setCurrentWidget(ui->page_feed);
+}
+
+void RSSFeedPlugin::openFeedInfo(){
+ QString ID = ui->combo_feed->currentData().toString();
+ if(ID.isEmpty()){ return; }
+ updateFeedInfo(ID);
+ ui->stackedWidget->setCurrentWidget(ui->page_feed_info);
+
+}
+
+void RSSFeedPlugin::openFeedNew(){
+ ui->line_new_url->setText("");
+ ui->stackedWidget->setCurrentWidget(ui->page_new_feed);
+}
+
+void RSSFeedPlugin::openSettings(){
+ //Sync the widget with the current settings
+ QSettings *set = LSession::handle()->DesktopPluginSettings();
+
+ ui->check_manual_sync->setChecked( set->value(setprefix+"manual_sync_only", false).toBool() );
+ int DI = set->value(setprefix+"default_interval_minutes", 60).toInt();
+ if(DI<1){ DI = 60; }
+ if( (DI%60) == 0 ){DI = DI/60; ui->combo_sync_units->setCurrentIndex(1); } //hourly setting
+ else{ ui->combo_sync_units->setCurrentIndex(1); } //minutes setting
+ ui->spin_synctime->setValue(DI);
+
+ //Now show the page
+ ui->stackedWidget->setCurrentWidget(ui->page_settings);
+}
+
+// - Feed Management
+void RSSFeedPlugin::addNewFeed(){
+ if(ui->line_new_url->text().isEmpty()){ return; } //nothing to add
+ //Validate the URL
+ QUrl url(ui->line_new_url->text());
+ if(!url.isValid()){
+ ui->line_new_url->setFocus();
+ return;
+ }
+ //Add the URL to the settings file for next login
+ QStringList feeds = LSession::handle()->DesktopPluginSettings()->value(setprefix+"currentfeeds",QStringList()).toStringList();
+ feeds << url.toString();
+ LSession::handle()->DesktopPluginSettings()->setValue(setprefix+"currentfeeds", feeds);
+
+ //Set this URL as the current selection
+ ui->combo_feed->setWhatsThis(url.toString()); //hidden field - will trigger an update in a moment
+ //Add the URL to the backend
+ RSS->addUrls(QStringList() << url.toString());
+ //UpdateFeedList(); //now re-load the feeds which are available
+
+ //Now go back to the main page
+ backToFeeds();
+}
+
+void RSSFeedPlugin::loadPreset(QAction *act){
+ ui->line_new_url->setText( act->whatsThis() );
+}
+
+void RSSFeedPlugin::removeFeed(){
+ QString ID = ui->page_feed_info->whatsThis();
+ if(ID.isEmpty()){ return; }
+ //Remove from the RSS feed object
+ RSSchannel info = RSS->dataForID(ID);
+ RSS->removeUrl(ID);
+ //Remove the URL from the settings file for next login
+ QStringList feeds = LSession::handle()->DesktopPluginSettings()->value(setprefix+"currentfeeds",QStringList()).toStringList();
+ feeds.removeAll(info.originalURL);
+ LSession::handle()->DesktopPluginSettings()->setValue(setprefix+"currentfeeds", feeds);
+ LSession::handle()->DesktopPluginSettings()->remove(setprefix+"feedReads/"+ID);
+ //Now go back to the main page
+ backToFeeds();
+}
+
+void RSSFeedPlugin::resyncFeeds(){
+ RSS->addUrls( LSession::handle()->DesktopPluginSettings()->value(setprefix+"currentfeeds",QStringList()).toStringList() );
+ RSS->syncNow();
+}
+
+// - Feed Interactions
+void RSSFeedPlugin::currentFeedChanged(){
+ QString ID = ui->combo_feed->currentData().toString();
+ //Remove the "unread" color/flag from the feed
+ ui->combo_feed->setItemData( ui->combo_feed->currentIndex(), QBrush(Qt::transparent) , Qt::BackgroundRole);
+ ui->combo_feed->setItemData( ui->combo_feed->currentIndex(), "", Qt::WhatsThisRole);
+ checkFeedNotify();
+ updateFeed(ID);
+}
+
+void RSSFeedPlugin::openFeedPage(){ //Open main website for feed
+ QString ID = ui->combo_feed->currentData().toString();
+ //Find the data associated with this feed
+ RSSchannel data = RSS->dataForID(ID);
+ QString url = data.link;
+ //qDebug() << "Open Feed Page:" << url;
+ //Now launch the browser
+ if(!url.isEmpty()){
+ LSession::LaunchApplication("lumina-open \""+url+"\"");
+ }
+}
+
+void RSSFeedPlugin::saveSettings(){
+ QSettings *set = LSession::handle()->DesktopPluginSettings();
+ set->setValue(setprefix+"manual_sync_only", ui->check_manual_sync->isChecked() );
+ int DI = ui->spin_synctime->value();
+ if(ui->combo_sync_units->currentIndex()==1){ DI = DI*60; } //convert from hours to minutes
+ set->setValue(setprefix+"default_interval_minutes", DI);
+ set->sync();
+
+ //Now go back to the feeds
+ backToFeeds();
+}
+
+//Feed Object interactions
+void RSSFeedPlugin::UpdateFeedList(){
+
+ QString activate = ui->combo_feed->whatsThis();
+ if(!activate.isEmpty()){ ui->combo_feed->setWhatsThis(""); }
+ if(activate.isEmpty()){ activate = ui->combo_feed->currentData().toString(); } // keep current item selected
+ //Now get/list all the available feeds
+ QStringList IDS = RSS->channels(); //this is pre-sorted by title of the feed
+ //qDebug() << "Update RSS Feed List:" << IDS << activate;
+ for(int i=0; i<IDS.length(); i++){
+ bool newitem = false;
+ if(ui->combo_feed->count()<=i){ newitem = true; }
+ else{
+ QString cid = ui->combo_feed->itemData(i).toString();
+ if(IDS[i]!=cid){
+ if(IDS.contains(cid)){ newitem = true; } //this item is just out of order
+ else{ ui->combo_feed->removeItem(i); } //item no longer is valid
+ }
+ }
+ if(newitem){
+ //Need to add a new item at this point in the menu
+ RSSchannel info = RSS->dataForID(IDS[i]);
+ if(info.title.isEmpty()){
+ //invalid/empty channel
+ ui->combo_feed->insertItem(i, IDS[i], IDS[i]); //just show the URL
+ }else{
+ ui->combo_feed->insertItem(i, info.icon, info.title, IDS[i]);
+ }
+ }
+ }
+ //Remove any extra items on the end of the list
+ for(int i=IDS.length(); i<ui->combo_feed->count(); i++){
+ ui->combo_feed->removeItem(i); i--;
+ }
+ //Now activate the proper item as needed
+ if(IDS.contains(activate)){
+ ui->combo_feed->setCurrentIndex( IDS.indexOf(activate) );
+ }
+ checkFeedNotify();
+}
+
+void RSSFeedPlugin::RSSItemChanged(QString ID){
+ for(int i=0; i<ui->combo_feed->count(); i++){
+ if(ui->combo_feed->itemData(i).toString()!=ID){ continue; }
+ RSSchannel info = RSS->dataForID(ID);
+ if(info.title.isEmpty()){
+ ui->combo_feed->setItemText(i, ID);
+ ui->combo_feed->setItemIcon(i, LXDG::findIcon("dialog-cancel","") );
+ }else{
+ ui->combo_feed->setItemText(i, info.title);
+ ui->combo_feed->setItemIcon(i, info.icon );
+ QColor color(Qt::transparent);
+ if( info.lastBuildDate > LSession::handle()->DesktopPluginSettings()->value(setprefix+"feedReads/"+ID,QDateTime()).toDateTime() ){
+ color = QColor(255,10,10,100); //semi-transparent red
+ ui->combo_feed->setItemData(i, "notify", Qt::WhatsThisRole);
+ }else{
+ ui->combo_feed->setItemData(i, "", Qt::WhatsThisRole);
+ }
+ ui->combo_feed->setItemData(i, QBrush(color) , Qt::BackgroundRole);
+ }
+ }
+ if(ID == ui->combo_feed->currentData().toString()){
+ currentFeedChanged(); //re-load the current feed
+ }else{
+ checkFeedNotify();
+ }
+}
+
+//==================
+// PUBLIC SLOTS
+//==================
+void RSSFeedPlugin::LocaleChange(){
+ ui->retranslateUi(this);
+ updateOptionsMenu();
+}
+void RSSFeedPlugin::ThemeChange(){
+ QTimer::singleShot(0,this, SLOT(loadIcons()));
+ updateOptionsMenu();
+}
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSFeedPlugin.h b/src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSFeedPlugin.h
new file mode 100644
index 00000000..68b36760
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSFeedPlugin.h
@@ -0,0 +1,72 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2016, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This plugin is a simple RSS feed reader for the desktop
+//===========================================
+#ifndef _LUMINA_DESKTOP_RSS_FEEDER_PLUGIN_H
+#define _LUMINA_DESKTOP_RSS_FEEDER_PLUGIN_H
+
+#include <QTimer>
+#include "../LDPlugin.h"
+
+#include "RSSObjects.h"
+
+namespace Ui{
+ class RSSFeedPlugin;
+};
+
+class RSSFeedPlugin : public LDPlugin{
+ Q_OBJECT
+public:
+ RSSFeedPlugin(QWidget* parent, QString ID);
+ ~RSSFeedPlugin();
+
+ virtual QSize defaultPluginSize(){
+ // The returned QSize is in grid points (typically 100 or 200 pixels square)
+ return QSize(3,3);
+ }
+private:
+ Ui::RSSFeedPlugin *ui;
+ QMenu *optionsMenu, *presetMenu;
+ QString setprefix; //settings prefix
+ RSSReader *RSS;
+
+ void updateOptionsMenu();
+ void checkFeedNotify(); //check if unread feeds are available and change the styling a bit as needed
+
+ //Simplification functions for loading feed info onto widgets
+ void updateFeed(QString ID);
+ void updateFeedInfo(QString ID);
+
+private slots:
+ void loadIcons();
+
+ //GUI slots
+ // - Page management
+ void backToFeeds();
+ void openFeedInfo();
+ void openFeedNew();
+ void openSettings();
+ // - Feed Management
+ void addNewFeed(); // the "add" button (current url in widget on page)
+ void loadPreset(QAction*); //the add-preset menu
+ void removeFeed(); // the "remove" button (current feed for page)
+ void resyncFeeds();
+ // - Feed Interactions
+ void currentFeedChanged();
+ void openFeedPage(); //Open the website in a browser
+ void saveSettings();
+
+ //Feed Object interactions
+ void UpdateFeedList();
+ void RSSItemChanged(QString ID);
+
+public slots:
+ void LocaleChange();
+ void ThemeChange();
+
+};
+#endif
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSFeedPlugin.ui b/src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSFeedPlugin.ui
new file mode 100644
index 00000000..45dac405
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSFeedPlugin.ui
@@ -0,0 +1,545 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>RSSFeedPlugin</class>
+ <widget class="QWidget" name="RSSFeedPlugin">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>238</width>
+ <height>278</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QStackedWidget" name="stackedWidget">
+ <property name="currentIndex">
+ <number>1</number>
+ </property>
+ <widget class="QWidget" name="page_feed">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QComboBox" name="combo_feed"/>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_options">
+ <property name="toolTip">
+ <string>View Options</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_lastupdate">
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_gotosite">
+ <property name="toolTip">
+ <string>Open Website</string>
+ </property>
+ <property name="text">
+ <string>More</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ <property name="arrowType">
+ <enum>Qt::NoArrow</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTextBrowser" name="text_feed">
+ <property name="undoRedoEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="html">
+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ <property name="openLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="page_feed_info">
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <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>5</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QPushButton" name="push_back1">
+ <property name="text">
+ <string>Back to Feeds</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Feed Information</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QTextBrowser" name="text_feed_info">
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_8">
+ <item>
+ <widget class="QPushButton" name="push_rm_feed">
+ <property name="text">
+ <string>Remove Feed</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="page_new_feed">
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QPushButton" name="push_back2">
+ <property name="text">
+ <string>Back to Feeds</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>New Feed Subscription</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_6">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="leftMargin">
+ <number>2</number>
+ </property>
+ <property name="topMargin">
+ <number>2</number>
+ </property>
+ <property name="rightMargin">
+ <number>2</number>
+ </property>
+ <property name="bottomMargin">
+ <number>2</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>RSS URL</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_10">
+ <item>
+ <widget class="QLineEdit" name="line_new_url"/>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_add_preset">
+ <property name="toolTip">
+ <string>Load a preset RSS Feed</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="push_add_url">
+ <property name="text">
+ <string>Add to Feeds</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="page_settings">
+ <layout class="QVBoxLayout" name="verticalLayout_7">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <item>
+ <widget class="QPushButton" name="push_back3">
+ <property name="text">
+ <string>Back to Feeds</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_3">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Feed Reader Settings</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_8">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="leftMargin">
+ <number>2</number>
+ </property>
+ <property name="topMargin">
+ <number>2</number>
+ </property>
+ <property name="rightMargin">
+ <number>2</number>
+ </property>
+ <property name="bottomMargin">
+ <number>2</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="check_manual_sync">
+ <property name="text">
+ <string>Manual Sync Only</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_4">
+ <property name="toolTip">
+ <string>Some RSS feeds may request custom update intervals instead of using this setting</string>
+ </property>
+ <property name="title">
+ <string>Default Sync Interval</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="leftMargin">
+ <number>2</number>
+ </property>
+ <property name="topMargin">
+ <number>2</number>
+ </property>
+ <property name="rightMargin">
+ <number>2</number>
+ </property>
+ <property name="bottomMargin">
+ <number>2</number>
+ </property>
+ <item>
+ <widget class="QSpinBox" name="spin_synctime">
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>60</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="combo_sync_units">
+ <property name="currentText">
+ <string>Hour(s)</string>
+ </property>
+ <property name="currentIndex">
+ <number>1</number>
+ </property>
+ <item>
+ <property name="text">
+ <string>Minutes</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Hour(s)</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_9">
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="push_save_settings">
+ <property name="text">
+ <string>Save Settings</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSObjects.cpp b/src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSObjects.cpp
new file mode 100644
index 00000000..654a005d
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSObjects.cpp
@@ -0,0 +1,275 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2016, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "RSSObjects.h"
+#include <QNetworkRequest>
+#include <QXmlStreamReader>
+
+#include "LSession.h"
+
+//============
+// PUBLIC
+//============
+RSSReader::RSSReader(QObject *parent, QString settingsPrefix) : QObject(parent){
+ NMAN = new QNetworkAccessManager(this);
+ connect(NMAN, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)) );
+ connect(NMAN, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)), this, SLOT(sslErrors(QNetworkReply*, const QList<QSslError>&)) );
+
+ setprefix = settingsPrefix;
+ syncTimer = new QTimer(this);
+ syncTimer->setInterval(300000); //5 minutes
+ connect(syncTimer, SIGNAL(timeout()), this, SLOT(checkTimes()));
+ syncTimer->start();
+}
+
+RSSReader::~RSSReader(){
+
+}
+
+//Information retrieval
+QStringList RSSReader::channels(){
+ QStringList urls = hash.keys();
+ QStringList ids;
+ //sort all the channels by title before output
+ for(int i=0; i<urls.length(); i++){
+ QString title = hash[urls[i]].title;
+ if(title.isEmpty()){ title = "ZZZ"; } //put currently-invalid ones at the end of the list
+ ids << title+" : "+urls[i];
+ }
+ ids.sort();
+ //Now strip off all the titles again to just get the IDs
+ for(int i=0; i<ids.length(); i++){
+ ids[i] = ids[i].section(" : ",-1);
+ }
+ return ids;
+}
+
+RSSchannel RSSReader::dataForID(QString ID){
+ if(hash.contains(ID)){ return hash[ID]; }
+ else{ return RSSchannel(); }
+}
+
+//Initial setup
+void RSSReader::addUrls(QStringList urls){
+ //qDebug() << "Add URLS:" << urls;
+ QStringList known = hash.keys();
+ int orig = known.length();
+ for(int i=0; i<orig; i++){ known << hash[known[i]].originalURL; }
+ for(int i=0; i<urls.length(); i++){
+ //Note: Make sure we get the complete URL form for accurate comparison later
+ QString url = QUrl(urls[i]).toString();
+ if(known.contains(url)){ continue; } //already handled
+ RSSchannel blank;
+ blank.originalURL = url;
+ hash.insert(url, blank); //put the empty struct into the hash for now
+ requestRSS(url); //startup the initial request for this url
+ }
+ emit newChannelsAvailable();
+}
+
+void RSSReader::removeUrl(QString ID){
+ if(hash.contains(ID)){ hash.remove(ID); }
+ emit newChannelsAvailable();
+}
+
+//=================
+// PUBLIC SLOTS
+//=================
+void RSSReader::syncNow(){
+ QStringList urls = hash.keys();
+ for(int i=0; i<urls.length(); i++){
+ requestRSS(urls[i]);
+ }
+}
+
+//=================
+// PRIVATE
+//=================
+void RSSReader::requestRSS(QString url){
+ if(!outstandingURLS.contains(url)){
+ //qDebug() << "Request URL:" << url;
+ NMAN->get( QNetworkRequest( QUrl(url) ) );
+ outstandingURLS << url;
+ }
+}
+
+//RSS parsing functions
+RSSchannel RSSReader::readRSS(QByteArray bytes){
+ //Note: We could expand this later to support multiple "channel"s per Feed
+ // but it seems like there is normally only one channel anyway
+ //qDebug() << "Read RSS:" << bytes.left(100);
+ QXmlStreamReader xml(bytes);
+ RSSchannel rssinfo;
+ //qDebug() << "Can Read XML Stream:" << !xml.hasError();
+ if(xml.readNextStartElement()){
+ //qDebug() << " - RSS Element:" << xml.name();
+ if(xml.name() == "rss" && (xml.attributes().value("version") =="2.0" || xml.attributes().value("version") =="0.91") ){
+ while(xml.readNextStartElement()){
+ //qDebug() << " - RSS Element:" << xml.name();
+ if(xml.name()=="channel"){ rssinfo = readRSSChannel(&xml); }
+ else{ xml.skipCurrentElement(); }
+ }
+ }
+ }
+ if(xml.hasError()){ qDebug() << " - XML Read Error:" << xml.errorString() << "\n" << bytes; }
+ return rssinfo;
+}
+RSSchannel RSSReader::readRSSChannel(QXmlStreamReader *rss){
+ RSSchannel info;
+ info.timetolive = -1;
+ while(rss->readNextStartElement()){
+ //qDebug() << " - RSS Element (channel):" <<rss->name();
+ if(rss->name()=="item"){ info.items << readRSSItem(rss); }
+ else if(rss->name()=="title"){ info.title = rss->readElementText(); }
+ else if(rss->name()=="link"){
+ QString txt = rss->readElementText();
+ if(!txt.isEmpty()){ info.link = txt; }
+ }
+ else if(rss->name()=="description"){ info.description = rss->readElementText(); }
+ else if(rss->name()=="lastBuildDate"){ info.lastBuildDate = RSSDateTime(rss->readElementText()); }
+ else if(rss->name()=="pubDate"){ info.lastPubDate = RSSDateTime(rss->readElementText()); }
+ else if(rss->name()=="image"){ readRSSImage(&info, rss); }
+ //else if(rss->name()=="skipHours"){ info.link = rss->readElementText(); }
+ //else if(rss->name()=="skipDays"){ info.link = rss->readElementText(); }
+ else if(rss->name()=="ttl"){ info.timetolive = rss->readElementText().toInt(); }
+ else{ rss->skipCurrentElement(); }
+ }
+ return info;
+}
+
+RSSitem RSSReader::readRSSItem(QXmlStreamReader *rss){
+ RSSitem item;
+ while(rss->readNextStartElement()){
+ //qDebug() << " - RSS Element (Item):" << rss->name();
+ if(rss->name()=="title"){ item.title = rss->readElementText(); }
+ else if(rss->name()=="link"){ item.link = rss->readElementText(); }
+ else if(rss->name()=="description"){ item.description = rss->readElementText(); }
+ else if(rss->name()=="comments"){ item.comments_url = rss->readElementText(); }
+ else if(rss->name()=="author"){
+ //Special handling - this field can contain both email and name
+ QString raw = rss->readElementText();
+ if(raw.contains("@")){
+ item.author_email = raw.split(" ").filter("@").first();
+ item.author = raw.remove(item.author_email).remove("(").remove(")").simplified(); //the name is often put within parentheses after the email
+ }else{ item.author = raw; }
+ }
+ else if(rss->name()=="guid"){ item.guid = rss->readElementText(); }
+ else if(rss->name()=="pubDate"){ item.pubdate = RSSDateTime(rss->readElementText()); }
+ else{ rss->skipCurrentElement(); }
+ }
+ return item;
+}
+
+void RSSReader::readRSSImage(RSSchannel *item, QXmlStreamReader *rss){
+ while(rss->readNextStartElement()){
+ //qDebug() << " - RSS Element (Image):" << rss->name();
+ if(rss->name()=="url"){ item->icon_url = rss->readElementText(); }
+ else if(rss->name()=="title"){ item->icon_title = rss->readElementText(); }
+ else if(rss->name()=="link"){ item->icon_link = rss->readElementText(); }
+ else if(rss->name()=="width"){ item->icon_size.setWidth(rss->readElementText().toInt()); }
+ else if(rss->name()=="height"){ item->icon_size.setHeight(rss->readElementText().toInt()); }
+ else if(rss->name()=="description"){ item->icon_description = rss->readElementText(); }
+ }
+ //Go ahead and kick off the request for the icon
+ if(!item->icon_url.isEmpty()){ requestRSS(item->icon_url); }
+}
+
+QDateTime RSSReader::RSSDateTime(QString datetime){
+ return QDateTime::fromString(datetime, Qt::RFC2822Date);
+}
+
+//=================
+// PRIVATE SLOTS
+//=================
+void RSSReader::replyFinished(QNetworkReply *reply){
+ QString url = reply->request().url().toString();
+ //qDebug() << "Got Reply:" << url;
+ QByteArray data = reply->readAll();
+ outstandingURLS.removeAll(url);
+ if(data.isEmpty()){
+ //qDebug() << "No data returned:" << url;
+ //see if the URL can be adjusted for known issues
+ bool handled = false;
+ QUrl redirecturl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
+ if(redirecturl.isValid() && (redirecturl.toString() != url )){
+ //New URL redirect - make the change and send a new request
+ QString newurl = redirecturl.toString();
+ //qDebug() << " - Redirect to:" << newurl;
+ if(hash.contains(url) && !hash.contains(newurl)){
+ hash.insert(newurl, hash.take(url) ); //just move the data over to the new url
+ requestRSS(newurl);
+ emit newChannelsAvailable();
+ handled = true;
+ }
+ }
+ if(!handled && hash.contains(url) ){
+ emit rssChanged(url);
+ }
+ return;
+ }
+
+ if(!hash.contains(url)){
+ //qDebug() << " - hash does not contain URL:" << url;
+ //URL removed from list while a request was outstanding?
+ //Could also be an icon fetch response
+ QStringList keys = hash.keys();
+ for(int i=0; i<keys.length(); i++){
+ //qDebug() << " - Check for icon URL:" << hash[keys[i]].icon_url;
+ if(hash[keys[i]].icon_url.toLower() == url.toLower()){ //needs to be case-insensitive
+ //Icon fetch response
+ RSSchannel info = hash[keys[i]];
+ QImage img = QImage::fromData(data);
+ info.icon = QIcon( QPixmap::fromImage(img) );
+ //qDebug() << "Got Icon response:" << url << info.icon;
+ hash.insert(keys[i], info); //insert back into the hash
+ emit rssChanged(keys[i]);
+ break;
+ }
+ }
+ reply->deleteLater();
+ }else{
+ //RSS reply
+ RSSchannel info = readRSS(data); //QNetworkReply can be used as QIODevice
+ reply->deleteLater(); //clean up
+ //Validate the info and announce any changes
+ if(info.title.isEmpty() || info.link.isEmpty() || info.description.isEmpty()){
+ qDebug() << "Missing XML Information:" << url << info.title << info.link << info.description;
+ return;
+ } //bad info/read
+ //Update the bookkeeping elements of the info
+ if(info.timetolive<=0){ info.timetolive = LSession::handle()->DesktopPluginSettings()->value(setprefix+"default_interval_minutes", 60).toInt(); }
+ if(info.timetolive <=0){ info.timetolive = 60; } //error in integer conversion from settings?
+ info.lastsync = QDateTime::currentDateTime(); info.nextsync = info.lastsync.addSecs(info.timetolive * 60);
+ //Now see if anything changed and save the info into the hash
+ bool changed = (hash[url].lastBuildDate.isNull() || (hash[url].lastBuildDate < info.lastBuildDate) );
+ bool newinfo = false;
+ if(changed){ newinfo = hash[url].title.isEmpty(); } //no previous info from this URL
+ info.originalURL = hash[url].originalURL; //make sure this info gets preserved across updates
+ hash.insert(url, info);
+ if(newinfo){ emit newChannelsAvailable(); } //new channel
+ else if(changed){ emit rssChanged(url); } //update to existing channel
+ }
+}
+
+void RSSReader::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors){
+ int ok = 0;
+ qDebug() << "SSL Errors Detected (RSS Reader):" << reply->url();
+ for(int i=0; i<errors.length(); i++){
+ if(errors[i].error()==QSslError::SelfSignedCertificate || errors[i].error()==QSslError::SelfSignedCertificateInChain){ ok++; }
+ else{ qDebug() << "Unhandled SSL Error:" << errors[i].errorString(); }
+ }
+ if(ok==errors.length()){ qDebug() << " - Permitted:" << reply->url(); reply->ignoreSslErrors(); }
+ else{ qDebug() << " - Denied:" << reply->url(); }
+}
+
+void RSSReader::checkTimes(){
+ if(LSession::handle()->DesktopPluginSettings()->value(setprefix+"manual_sync_only", false).toBool()){ return; }
+ QStringList urls = hash.keys();
+ QDateTime cdt = QDateTime::currentDateTime();
+ for(int i=0; i<urls.length(); i++){
+ if(hash[urls[i]].nextsync < cdt){ requestRSS(urls[i]); }
+ }
+}
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSObjects.h b/src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSObjects.h
new file mode 100644
index 00000000..c0e72e18
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/rssreader/RSSObjects.h
@@ -0,0 +1,101 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2016, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_DESKTOP_RSS_READER_PLUGIN_OBJECT_H
+#define _LUMINA_DESKTOP_RSS_READER_PLUGIN_OBJECT_H
+
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QString>
+#include <QDateTime>
+#include <QList>
+#include <QIcon>
+#include <QTimer>
+#include <QXmlStreamReader> //Contained in the Qt "core" module - don't need the full "xml" module for this
+#include <QSslError>
+
+struct RSSitem{
+ //Required Fields
+ QString title, link, description;
+
+ //Optional Fields
+ QString comments_url, author_email, author, guid;
+ QDateTime pubdate; //when the item was published
+ //IGNORED INFO from RSS2 spec: "category", "source", "enclosure"
+};
+
+struct RSSchannel{
+ //Required fields
+ QString title, link, description;
+
+ //Optional Fields
+ QDateTime lastBuildDate, lastPubDate; //last build/publish dates
+ // - channel refresh information
+ int timetolive; //in minutes - time until next sync should be performed
+ //QList<int> skiphours;
+ //QStringList skipdays;
+ // - icon info
+ QIcon icon;
+ QString icon_url, icon_title, icon_link, icon_description;
+ QSize icon_size;
+ //All items within this channel
+ QList<RSSitem> items;
+
+ //Optional RSS2 elements ignored:
+ // "cloud", "textInput", "rating", "language", "copyright", "managingEditor", "webMaster",
+ // "category", "generator", "docs"
+
+ //Internal data for bookkeeping
+ QDateTime lastsync, nextsync;
+ QString originalURL; //in case it was redirected to some "fixed" url later
+};
+
+class RSSReader : public QObject{
+ Q_OBJECT
+public:
+ RSSReader(QObject *parent, QString settingsPrefix);
+ ~RSSReader();
+
+ //Information retrieval
+ QStringList channels(); //returns all ID's
+ RSSchannel dataForID(QString ID);
+
+ //Initial setup
+ void addUrls(QStringList urls);
+ void removeUrl(QString ID);
+
+public slots:
+ void syncNow(); //not generally needed
+
+private:
+ //Internal data objects
+ QHash<QString, RSSchannel> hash; // ID/data
+ QString setprefix;
+ QTimer *syncTimer;
+ QNetworkAccessManager *NMAN;
+ QStringList outstandingURLS;
+
+ //Network request function
+ void requestRSS(QString url);
+
+ //RSS parsing functions
+ RSSchannel readRSS(QByteArray bytes);
+ RSSchannel readRSSChannel(QXmlStreamReader *rss);
+ RSSitem readRSSItem(QXmlStreamReader *rss);
+ void readRSSImage(RSSchannel *item, QXmlStreamReader *rss);
+ QDateTime RSSDateTime(QString datetime);
+
+private slots:
+ void replyFinished(QNetworkReply *reply);
+ void sslErrors(QNetworkReply *reply, const QList<QSslError> &errors);
+ void checkTimes();
+
+signals:
+ void rssChanged(QString); //ID
+ void newChannelsAvailable();
+};
+
+#endif
diff --git a/src-qt5/core/lumina-desktop/panel-plugins/appmenu/LAppMenuPlugin.cpp b/src-qt5/core/lumina-desktop/panel-plugins/appmenu/LAppMenuPlugin.cpp
index 318d03fa..7c9b7ab0 100644
--- a/src-qt5/core/lumina-desktop/panel-plugins/appmenu/LAppMenuPlugin.cpp
+++ b/src-qt5/core/lumina-desktop/panel-plugins/appmenu/LAppMenuPlugin.cpp
@@ -34,7 +34,7 @@ void LAppMenuPlugin::updateButtonVisuals(){
button->setToolTip( tr("Quickly launch applications or open files"));
button->setText( tr("Applications") );
//Use the PC-BSD icon by default (or the Lumina icon for non-PC-BSD systems)
- button->setIcon( LXDG::findIcon("pcbsd","Lumina-DE") );
+ button->setIcon( LXDG::findIcon("start-here-lumina","Lumina-DE") );
}
// ========================
@@ -131,4 +131,3 @@ void LAppMenuPlugin::UpdateMenu(){
tmpact->setWhatsThis("internal::logout");
}
-
diff --git a/src-qt5/core/lumina-desktop/panel-plugins/systemstart/LStartButton.cpp b/src-qt5/core/lumina-desktop/panel-plugins/systemstart/LStartButton.cpp
index e08ef1c8..d57846e2 100644
--- a/src-qt5/core/lumina-desktop/panel-plugins/systemstart/LStartButton.cpp
+++ b/src-qt5/core/lumina-desktop/panel-plugins/systemstart/LStartButton.cpp
@@ -42,7 +42,7 @@ LStartButtonPlugin::~LStartButtonPlugin(){
void LStartButtonPlugin::updateButtonVisuals(){
button->setToolTip(tr(""));
button->setText( SYSTEM::user() );
- button->setIcon( LXDG::findIcon("pcbsd","Lumina-DE") ); //force icon refresh
+ button->setIcon( LXDG::findIcon("start-here-lumina","Lumina-DE") ); //force icon refresh
}
void LStartButtonPlugin::updateQuickLaunch(QStringList apps){
@@ -117,4 +117,3 @@ void LStartButtonPlugin::openMenu(){
void LStartButtonPlugin::closeMenu(){
menu->hide();
}
-
diff --git a/src-qt5/core/lumina-desktop/panel-plugins/taskmanager/LTaskButton.cpp b/src-qt5/core/lumina-desktop/panel-plugins/taskmanager/LTaskButton.cpp
index a67ef5d6..7e2e53de 100644
--- a/src-qt5/core/lumina-desktop/panel-plugins/taskmanager/LTaskButton.cpp
+++ b/src-qt5/core/lumina-desktop/panel-plugins/taskmanager/LTaskButton.cpp
@@ -122,8 +122,12 @@ void LTaskButton::UpdateButton(){
//single window
this->setPopupMode(QToolButton::DelayedPopup);
this->setMenu(actMenu);
- if(showText){ this->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); this->setText( WINLIST[0].text()); }
- else if(noicon){ this->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); this->setText( cname ); }
+ if(showText){
+ QString txt = WINLIST[0].text();
+ if(txt.length()>30){ txt.truncate(27); txt.append("..."); }
+ else if(txt.length()<30){ txt = txt.leftJustified(30, ' '); }
+ this->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); this->setText(txt);
+ }else if(noicon){ this->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); this->setText( cname ); }
else{ this->setToolButtonStyle(Qt::ToolButtonIconOnly); this->setText(""); }
this->setToolTip(WINLIST[0].text());
}else if(WINLIST.length() > 1){
diff --git a/src-qt5/core/lumina-open/LFileDialog.cpp b/src-qt5/core/lumina-open/LFileDialog.cpp
index c0417935..9ec94bf5 100644
--- a/src-qt5/core/lumina-open/LFileDialog.cpp
+++ b/src-qt5/core/lumina-open/LFileDialog.cpp
@@ -15,8 +15,8 @@ LFileDialog::LFileDialog(QWidget *parent) : QDialog(parent), ui(new Ui::LFileDia
appExec.clear();
appPath.clear();
appFile.clear();
- QSettings::setPath(QSettings::NativeFormat, QSettings::UserScope, QDir::homePath()+"/.lumina");
- settings = new QSettings("LuminaDE", "lumina-open",this);
+ //QSettings::setPath(QSettings::NativeFormat, QSettings::UserScope, QDir::homePath()+"/.lumina");
+ settings = new QSettings("lumina-desktop", "lumina-open", this);
//Connect the signals/slots
connect(ui->combo_apps, SIGNAL(currentIndexChanged(int)), this, SLOT(updateUI()) );
connect(ui->radio_rec, SIGNAL(toggled(bool)), this, SLOT(radioChanged()) );
@@ -46,6 +46,7 @@ void LFileDialog::setFileInfo(QString filename, QString extension, bool isFile){
//static functions
QString LFileDialog::getDefaultApp(QString extension){
+ qDebug() << "Get Default App:" << extension;
QSettings::setPath(QSettings::NativeFormat, QSettings::UserScope, QDir::homePath()+"/.lumina");
if(extension.contains("/")){
return LXDG::findDefaultAppForMime(extension);
@@ -66,7 +67,7 @@ void LFileDialog::setDefaultApp(QString extension, QString appFile){
}else{
QSettings("LuminaDE", "lumina-open").setValue("default/"+extension,appFile);
}
- }
+ }
}
// -----------
@@ -283,4 +284,3 @@ void LFileDialog::on_tool_findBin_clicked(){
void LFileDialog::on_line_bin_textChanged(){
updateUI();
}
-
diff --git a/src-qt5/core/lumina-open/main.cpp b/src-qt5/core/lumina-open/main.cpp
index a323e075..7a7fef19 100644
--- a/src-qt5/core/lumina-open/main.cpp
+++ b/src-qt5/core/lumina-open/main.cpp
@@ -101,6 +101,7 @@ QString cmdFromUser(int argc, char **argv, QString inFile, QString extension, QS
//qDebug() << "Matches:" << matches;
for(int i=0; i<matches.length(); i++){
defApp = LXDG::findDefaultAppForMime(matches[i]);
+ //qDebug() << "MimeType:" << matches[i] << defApp;
if(!defApp.isEmpty()){ extension = matches[i]; break; }
else if(i+1==matches.length()){ extension = matches[0]; }
}
@@ -226,6 +227,7 @@ void getCMD(int argc, char ** argv, QString& binary, QString& args, QString& pat
//Now check what type of file this is
if(QFile::exists(inFile)){ isFile=true; }
else if(QFile::exists(QDir::currentPath()+"/"+inFile)){isFile=true; inFile = QDir::currentPath()+"/"+inFile;} //account for relative paths
+ else if(inFile.startsWith("mailto:")){ isUrl= true; }
else if(QUrl(inFile).isValid() && !inFile.startsWith("/") ){ isUrl=true; }
if( !isFile && !isUrl ){ ShowErrorDialog( argc, argv, QString(QObject::tr("Invalid file or URL: %1")).arg(inFile) ); }
//Determing the type of file (extension)
@@ -239,7 +241,7 @@ void getCMD(int argc, char ** argv, QString& binary, QString& args, QString& pat
else if(info.isExecutable() && extension.isEmpty()){ extension="binary"; }
else if(extension!="desktop"){ extension="mimetype"; } //flag to check for mimetype default based on file
}
- else if(isUrl && inFile.startsWith("mailto:")){ extension = "email"; }
+ else if(isUrl && inFile.startsWith("mailto:")){ extension = "application/email"; }
else if(isUrl && inFile.contains("://") ){ extension = "x-scheme-handler/"+inFile.section("://",0,0); }
else if(isUrl && inFile.startsWith("www.")){ extension = "x-scheme-handler/http"; inFile.prepend("http://"); } //this catches partial (but still valid) URL's ("www.<something>" for instance)
//qDebug() << "Input:" << inFile << isFile << isUrl << extension;
@@ -314,7 +316,7 @@ void getCMD(int argc, char ** argv, QString& binary, QString& args, QString& pat
cmd.replace("%F","\""+inFile+"\"");
}else if( (cmd.contains("%U") || cmd.contains("%u")) ){
//Apply any special field replacements for the desired format
- if(!inFile.contains("://")){ inFile.prepend("file://"); } //local file - add the extra flag
+ if(!inFile.contains("://") && !isUrl){ inFile.prepend("file://"); } //local file - add the extra flag
inFile.replace(" ", "%20");
//Now replace the field codes
cmd.replace("%u","\""+inFile+"\"");
diff --git a/src-qt5/core/lumina-session/main.cpp b/src-qt5/core/lumina-session/main.cpp
index 8f89e95c..27eaf537 100644
--- a/src-qt5/core/lumina-session/main.cpp
+++ b/src-qt5/core/lumina-session/main.cpp
@@ -40,7 +40,9 @@ int main(int argc, char ** argv)
//Start X11 if needed
//Configure X11 monitors if needed
-
+ if(LUtils::isValidBinary("lumina-xconfig")){
+ QProcess::execute("lumina-xconfig --reset-monitors");
+ }
//Startup the session
QCoreApplication a(argc, argv);
LSession sess;
diff --git a/src-qt5/desktop-utils/lumina-fm/FODialog.cpp b/src-qt5/desktop-utils/lumina-fm/FODialog.cpp
index b9acdc03..b03f1b56 100644
--- a/src-qt5/desktop-utils/lumina-fm/FODialog.cpp
+++ b/src-qt5/desktop-utils/lumina-fm/FODialog.cpp
@@ -193,7 +193,7 @@ QStringList FOWorker::subfiles(QString dirpath, bool dirsfirst){
for(int i=0; i<subdirs.length(); i++){ out << subfiles(dir.absoluteFilePath(subdirs[i]), dirsfirst); }
}
//List the files
- QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden, QDir::NoSort);
+ QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDir::NoSort);
for(int i=0; i<files.length(); i++){ out << dir.absoluteFilePath(files[i]); }
if(!dirsfirst){
diff --git a/src-qt5/desktop-utils/lumina-fm/MainUI.cpp b/src-qt5/desktop-utils/lumina-fm/MainUI.cpp
index 010df40d..a4d2db28 100644
--- a/src-qt5/desktop-utils/lumina-fm/MainUI.cpp
+++ b/src-qt5/desktop-utils/lumina-fm/MainUI.cpp
@@ -718,10 +718,10 @@ void MainUI::OpenImages(LFileInfoList list){
void MainUI::OpenTerminal(QString dirpath){
//we use the application defined as the default terminal
- QSettings sessionsettings( QSettings::UserScope, "LuminaDE","sessionsettings", this);
+ //QSettings sessionsettings( QSettings::UserScope, "LuminaDE","sessionsettings", this);
//xterm remains the default
- QString defTerminal = sessionsettings.value("default-terminal", "xterm").toString();
- //qDebug() << "Found default terminal:" << defTerminal;
+ QString defTerminal = LXDG::findDefaultAppForMime("application/terminal"); //sessionsettings.value("default-terminal", "xterm").toString();
+ qDebug() << "Found default terminal:" << defTerminal;
//Now get the exec string and run it
QString cmd = LUtils::GenerateOpenTerminalExec(defTerminal, dirpath);
//qDebug() << "Starting Terminal with command:" << cmd;
diff --git a/src-qt5/desktop-utils/lumina-fm/lumina-fm.pro b/src-qt5/desktop-utils/lumina-fm/lumina-fm.pro
index 9bb90a0e..5e0717f8 100644
--- a/src-qt5/desktop-utils/lumina-fm/lumina-fm.pro
+++ b/src-qt5/desktop-utils/lumina-fm/lumina-fm.pro
@@ -34,12 +34,11 @@ FORMS += MainUI.ui \
widgets/SlideshowWidget.ui \
widgets/DirWidget.ui
-# RESOURCES+= lumina-fm.qrc
+icons.files = Insight-FileManager.png
+icons.path = $${L_SHAREDIR}/pixmaps
LIBS += -lLuminaUtils
-DEPENDPATH += ../libLumina
-
TRANSLATIONS = i18n/lumina-fm_af.ts \
i18n/lumina-fm_ar.ts \
i18n/lumina-fm_az.ts \
@@ -109,7 +108,7 @@ dotrans.extra=cd i18n && $${LRELEASE} -nounfinished *.ts && cp *.qm $(INSTALL_RO
desktop.files=lumina-fm.desktop
desktop.path=$${L_SHAREDIR}/applications/
-INSTALLS += target dotrans desktop
+INSTALLS += target dotrans desktop icons
NO_I18N{
INSTALLS -= dotrans
diff --git a/src-qt5/desktop-utils/lumina-terminal/TerminalWidget.cpp b/src-qt5/desktop-utils/lumina-terminal/TerminalWidget.cpp
index 9d0162a6..e8f80f88 100644
--- a/src-qt5/desktop-utils/lumina-terminal/TerminalWidget.cpp
+++ b/src-qt5/desktop-utils/lumina-terminal/TerminalWidget.cpp
@@ -18,7 +18,7 @@
TerminalWidget::TerminalWidget(QWidget *parent, QString dir) : QTextEdit(parent){
//Setup the text widget
- this->setStyleSheet("background: black;");
+ this->setStyleSheet("background: black; color: white;");
this->setLineWrapMode(QTextEdit::WidgetWidth);
this->setAcceptRichText(false);
this->setOverwriteMode(true);
bgstack15