aboutsummaryrefslogtreecommitdiff
path: root/src-qt5/core/lumina-desktop/desktop-plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src-qt5/core/lumina-desktop/desktop-plugins')
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/LDPlugin.cpp57
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/LDPlugin.h155
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/NewDP.h60
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/SamplePlugin.h38
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/applauncher/AppLauncherPlugin.cpp140
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/applauncher/AppLauncherPlugin.h59
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/applauncher/OutlineToolButton.h98
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/audioplayer/PlayerWidget.cpp269
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/audioplayer/PlayerWidget.h84
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/audioplayer/PlayerWidget.ui182
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/calendar/CalendarPlugin.h58
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/desktop-plugins.pri19
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/desktopview/DesktopViewPlugin.cpp215
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/desktopview/DesktopViewPlugin.h55
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/messagecenter/LXDG-DBusNotifier.h17
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/messagecenter/MessageCenter.cpp90
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/messagecenter/MessageCenter.h48
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/notepad/NotepadPlugin.cpp329
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/notepad/NotepadPlugin.h66
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/quickcontainer/QuickDPlugin.h51
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/systemmonitor/MonitorWidget.cpp63
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/systemmonitor/MonitorWidget.h62
-rw-r--r--src-qt5/core/lumina-desktop/desktop-plugins/systemmonitor/MonitorWidget.ui143
23 files changed, 2358 insertions, 0 deletions
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/LDPlugin.cpp b/src-qt5/core/lumina-desktop/desktop-plugins/LDPlugin.cpp
new file mode 100644
index 00000000..69505705
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/LDPlugin.cpp
@@ -0,0 +1,57 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014-2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "LDPlugin.h"
+
+#include "../LSession.h"
+#include <LuminaXDG.h>
+
+LDPlugin::LDPlugin(QWidget *parent, QString id) : QFrame(parent){
+ PLUGID=id;
+ prefix = id.replace("/","_")+"/";
+ //qDebug() << "ID:" << PLUGID << prefix;
+ settings = LSession::handle()->DesktopPluginSettings();
+ //Setup the plugin system control menu
+ menu = new QMenu(this);
+ setupMenu();
+ //Setup the internal timer for when to start/stop drag events
+ dragTimer = new QTimer(this);
+ dragTimer->setSingleShot(true);
+ dragTimer->setInterval(500); //1/2 second to show the plugin menu
+ connect(dragTimer, SIGNAL(timeout()), this, SLOT(showPluginMenu()));
+ //Use plugin-specific values for stylesheet control (applauncher, desktopview, etc...)
+ this->setObjectName(id.section("---",0,0).section("::",0,0));
+ this->setContextMenuPolicy(Qt::CustomContextMenu);
+ this->setMouseTracking(false); //only catch mouse movement events if the mouse is clicked/held on the plugin
+ connect(QApplication::instance(), SIGNAL(LocaleChanged()), this, SLOT(LocaleChange()) );
+ connect(QApplication::instance(), SIGNAL(IconThemeChanged()), this, SLOT(ThemeChange()) );
+ connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showPluginMenu()) );
+}
+
+void LDPlugin::setupMenu(){
+ menu->clear();
+ menu->addAction( LXDG::findIcon("transform-move",""), tr("Start Moving Item"), this, SLOT(slotStartMove()) );
+ menu->addAction( LXDG::findIcon("transform-scale",""), tr("Start Resizing Item"), this, SLOT(slotStartResize()) );
+ menu->addSeparator();
+ menu->addAction( LXDG::findIcon("zoom-in",""), tr("Increase Item Sizes"), this, SIGNAL(IncreaseIconSize()) );
+ menu->addAction( LXDG::findIcon("zoom-out",""), tr("Decrease Item Sizes"), this, SIGNAL(DecreaseIconSize()) );
+ menu->addSeparator();
+ menu->addAction( LXDG::findIcon("edit-delete",""), tr("Remove Item"), this, SLOT(slotRemovePlugin()) );
+}
+
+/*void LDPlugin::setInitialSize(int width, int height){
+ //Note: Only run this in the plugin initization routine:
+ // if the plugin is completely new (first time used), it will be this size
+ if(settings->allKeys().filter(prefix+"location").isEmpty()){
+ //Brand new plugin: set initial size
+ //qDebug() << "Setting Initial Size:" << PLUGID << width << height;
+ settings->setValue(prefix+"location/width",width);
+ settings->setValue(prefix+"location/height",height);
+ settings->sync();
+ }
+ //Now make sure the plugin is the saved size right away
+ this->resize( settings->value(prefix+"location/width").toInt(), settings->value(prefix+"location/height").toInt());
+}*/ \ No newline at end of file
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/LDPlugin.h b/src-qt5/core/lumina-desktop/desktop-plugins/LDPlugin.h
new file mode 100644
index 00000000..27fcaa24
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/LDPlugin.h
@@ -0,0 +1,155 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014-2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This class is the generic container layout for all desktop plugins
+// Simply subclass this when creating a new plugin to enable correct
+// visibility and usage within the desktop window
+//===========================================
+// WARNING: Do *not* setup a custom context menu for the entire plugins area!
+// This can prevent access to the general desktop context menu if
+// the plugin was maximized to fill the desktop area!
+//===========================================
+#ifndef _LUMINA_DESKTOP_DESKTOP_PLUGIN_H
+#define _LUMINA_DESKTOP_DESKTOP_PLUGIN_H
+
+#include <QObject>
+#include <QFrame>
+#include <QWidget>
+#include <QString>
+#include <QDebug>
+#include <QSettings>
+#include <QMoveEvent>
+#include <QResizeEvent>
+#include <QMouseEvent>
+#include <QTimer>
+#include <QMenu>
+
+class LDPlugin : public QFrame{
+ Q_OBJECT
+
+private:
+ QString PLUGID, prefix;
+ QSettings *settings;
+ QMenu *menu;
+ QTimer *dragTimer;
+
+ void setupMenu();
+
+public:
+ LDPlugin(QWidget *parent = 0, QString id="unknown");
+
+ ~LDPlugin(){}
+
+ QString ID(){
+ return PLUGID;
+ }
+
+ virtual QSize defaultPluginSize(){
+ //This needs to be re-implemented in the subclassed plugin
+ // The returned QSize is in grid points (typically 100 or 200 pixels square)
+ return QSize(1,1); //1x1 grid size
+ }
+
+ void savePluginGeometry(QRect geom){
+ settings->setValue(prefix+"geometry/desktopGridPoints", geom);
+ settings->sync();
+ }
+
+ QRect loadPluginGeometry(){
+ return settings->value(prefix+"geometry/desktopGridPoints", QRect()).toRect();
+ }
+
+ void saveSetting(QString var, QVariant val){
+ //qDebug() << "Saving Setting:" << prefix+var+QString(" = ")+val.toString();
+ settings->setValue(prefix+var, val);
+ settings->sync();
+ }
+
+ QVariant readSetting(QString var, QVariant defaultval){
+ return settings->value(prefix+var, defaultval);
+ }
+
+ virtual void Cleanup(){
+ //This needs to be re-implemented in the subclassed plugin
+ //This is where any last-minute changes are performed before a plugin is removed permanently
+ //Note1: This is *not* called if the plugin is being temporarily closed
+ //Note2: All the settings for this plugin will be automatically removed after this is finished
+ }
+
+ void removeSettings(bool permanent = false){ //such as when a plugin is deleted
+ if(permanent){ Cleanup(); }
+ QStringList list = settings->allKeys().filter(prefix);
+ for(int i=0; i<list.length(); i++){ settings->remove(list[i]); }
+
+ }
+
+public slots:
+ virtual void LocaleChange(){
+ //This needs to be re-implemented in the subclassed plugin
+ //This is where all text is set/translated
+ setupMenu();
+ }
+ virtual void ThemeChange(){
+ //This needs to be re-implemented in the subclassed plugin
+ //This is where all the visuals are set if using Theme-dependant icons.
+ setupMenu();
+ }
+ void showPluginMenu(){
+ emit CloseDesktopMenu();
+ menu->popup( QCursor::pos() );
+ }
+
+signals:
+ void OpenDesktopMenu();
+ void CloseDesktopMenu();
+ void PluginResized();
+
+ //Signals for communication with the desktop layout system (not generally used by hand)
+ void StartMoving(QString); //ID of plugin
+ void StartResizing(QString); //ID of plugin
+ void RemovePlugin(QString); //ID of plugin
+ void IncreaseIconSize(); // only used for desktop icons
+ void DecreaseIconSize(); // only used for desktop icons
+
+private slots:
+ void slotStartMove(){
+ QCursor::setPos( this->mapToGlobal(QPoint(this->width()/2, this->height()/2)) );
+ emit StartMoving(PLUGID);
+ }
+
+ void slotStartResize(){
+ QCursor::setPos( this->mapToGlobal(QPoint(this->width()/2, this->height()/2)) );
+ emit StartResizing(PLUGID);
+ }
+
+ void slotRemovePlugin(){
+ removeSettings(true);
+ emit RemovePlugin(PLUGID);
+ }
+
+protected:
+ void mousePressEvent(QMouseEvent *ev){
+ if(!dragTimer->isActive() && ev->buttons().testFlag(Qt::LeftButton) ){ dragTimer->start(); }
+ QWidget::mousePressEvent(ev);
+ }
+ void mouseReleaseEvent(QMouseEvent *ev){
+ if(dragTimer->isActive()){ dragTimer->stop(); }
+ QWidget::mouseReleaseEvent(ev);
+ }
+ void mouseMoveEvent(QMouseEvent *ev){
+ if(ev->buttons().testFlag(Qt::LeftButton)){
+ if(dragTimer->isActive()){ dragTimer->stop(); }
+ slotStartMove();
+ }
+ QWidget::mouseMoveEvent(ev);
+ }
+ void resizeEvent(QResizeEvent *ev){
+ emit PluginResized();
+ QFrame::resizeEvent(ev); //do normal processing
+ }
+};
+
+#endif
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/NewDP.h b/src-qt5/core/lumina-desktop/desktop-plugins/NewDP.h
new file mode 100644
index 00000000..a12341bb
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/NewDP.h
@@ -0,0 +1,60 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This class is the interface to load all the different desktop plugins
+//===========================================
+#ifndef _LUMINA_DESKTOP_NEW_DESKTOP_PLUGIN_H
+#define _LUMINA_DESKTOP_NEW_DESKTOP_PLUGIN_H
+
+#include <QDebug>
+
+//List all the individual plugin includes here
+#include "LDPlugin.h"
+//#include "SamplePlugin.h"
+#include "calendar/CalendarPlugin.h"
+#include "applauncher/AppLauncherPlugin.h"
+#include "desktopview/DesktopViewPlugin.h"
+#include "notepad/NotepadPlugin.h"
+#include "audioplayer/PlayerWidget.h"
+#include "systemmonitor/MonitorWidget.h"
+//#include "quickcontainer/QuickDPlugin.h"
+//#include "messagecenter/MessageCenter.h"
+
+class NewDP{
+public:
+ static LDPlugin* createPlugin(QString plugin, QWidget* parent=0){
+ //qDebug() << "Create Plugin:" << plugin;
+ LDPlugin *plug = 0;
+ /*if(plugin.section("---",0,0)=="sample"){
+ plug = new SamplePlugin(parent, plugin);
+ }else */
+ if(plugin.section("---",0,0)=="calendar"){
+ plug = new CalendarPlugin(parent, plugin);
+ }else if(plugin.section("---",0,0).section("::",0,0)=="applauncher"){
+ //This plugin can be pre-initialized to a file path after the "::" delimiter
+ plug = new AppLauncherPlugin(parent, plugin);
+ }else if(plugin.section("---",0,0)=="desktopview"){
+ plug = new DesktopViewPlugin(parent, plugin);
+ }else if(plugin.section("---",0,0)=="notepad"){
+ plug = new NotePadPlugin(parent, plugin);
+ }else if(plugin.section("---",0,0)=="audioplayer"){
+ plug = new AudioPlayerPlugin(parent, plugin);
+ }else if(plugin.section("---",0,0)=="systemmonitor"){
+ plug = new SysMonitorPlugin(parent, plugin);
+ //}else if(plugin.section("---",0,0)=="messagecenter"){
+ //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{
+ qWarning() << "Invalid Desktop Plugin:"<<plugin << " -- Ignored";
+ }
+ //qDebug() << " -- done";
+ return plug;
+ }
+
+};
+
+#endif
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/SamplePlugin.h b/src-qt5/core/lumina-desktop/desktop-plugins/SamplePlugin.h
new file mode 100644
index 00000000..4a790c2d
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/SamplePlugin.h
@@ -0,0 +1,38 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This class is a quick sample desktop plugin
+//===========================================
+#ifndef _LUMINA_DESKTOP_DESKTOP_PLUGIN_SAMPLE_H
+#define _LUMINA_DESKTOP_DESKTOP_PLUGIN_SAMPLE_H
+
+#include <QPushButton>
+#include <QMessageBox>
+#include <QVBoxLayout>
+#include "LDPlugin.h"
+
+class SamplePlugin : public LDPlugin{
+ Q_OBJECT
+public:
+ SamplePlugin(QWidget* parent, QString ID) : LDPlugin(parent, ID){
+ this->setLayout( new QVBoxLayout());
+ this->layout()->setContentsMargins(0,0,0,0);
+ button = new QPushButton("sample");
+ this->layout()->addWidget(button);
+ connect(button, SIGNAL(clicked()), this, SLOT(showMessage()) );
+ }
+
+ ~SamplePlugin(){}
+
+private:
+ QPushButton *button;
+
+private slots:
+ void showMessage(){
+ QMessageBox::information(this,"sample","sample desktop plugin works");
+ }
+};
+#endif
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/applauncher/AppLauncherPlugin.cpp b/src-qt5/core/lumina-desktop/desktop-plugins/applauncher/AppLauncherPlugin.cpp
new file mode 100644
index 00000000..101abd31
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/applauncher/AppLauncherPlugin.cpp
@@ -0,0 +1,140 @@
+#include "AppLauncherPlugin.h"
+#include "../../LSession.h"
+#include "OutlineToolButton.h"
+
+#define OUTMARGIN 10 //special margin for fonts due to the outlining effect from the OutlineToolbutton
+
+AppLauncherPlugin::AppLauncherPlugin(QWidget* parent, QString ID) : LDPlugin(parent, ID){
+ QVBoxLayout *lay = new QVBoxLayout();
+ this->setLayout(lay);
+ lay->setContentsMargins(0,0,0,0);
+ button = new OutlineToolButton(this);
+ button->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
+ button->setAutoRaise(true);
+ button->setText("...\n..."); //Need to set something here so that initial sizing works properly
+ button->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
+ lay->addWidget(button, 0, Qt::AlignCenter);
+ connect(button, SIGNAL(DoubleClicked()), this, SLOT(buttonClicked()) );
+ button->setContextMenuPolicy(Qt::NoContextMenu);
+ watcher = new QFileSystemWatcher(this);
+ connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT( loadButton()) );
+
+ QTimer::singleShot(200,this, SLOT(loadButton()) );
+}
+
+void AppLauncherPlugin::Cleanup(){
+ //This is run only when the plugin was forcibly closed/removed
+
+}
+
+void AppLauncherPlugin::loadButton(){
+ QString def = this->ID().section("::",1,50).section("---",0,0).simplified();
+ QString path = this->readSetting("applicationpath",def).toString(); //use the default if necessary
+ //qDebug() << "Default Application Launcher:" << def << path;
+ bool ok = QFile::exists(path);
+ if(!ok){ emit RemovePlugin(this->ID()); return;}
+ int icosize = this->height()-4 - 2.2*button->fontMetrics().height();
+ button->setFixedSize( this->width()-4, this->height()-4);
+ button->setIconSize( QSize(icosize,icosize) );
+ QString txt;
+ if(path.endsWith(".desktop") && ok){
+ XDGDesktop file = LXDG::loadDesktopFile(path, ok);
+ if(path.isEmpty() || !QFile::exists(path) || !ok){
+ button->setWhatsThis("");
+ button->setIcon( QIcon(LXDG::findIcon("quickopen-file","").pixmap(QSize(icosize,icosize)).scaledToHeight(icosize, Qt::SmoothTransformation) ) );
+ txt = tr("Click to Set");
+ if(!watcher->files().isEmpty()){ watcher->removePaths(watcher->files()); }
+ }else{
+ button->setWhatsThis(file.filePath);
+ button->setIcon( QIcon(LXDG::findIcon(file.icon,"quickopen").pixmap(QSize(icosize,icosize)).scaledToHeight(icosize, Qt::SmoothTransformation) ) );
+ txt = file.name;
+ if(!watcher->files().isEmpty()){ watcher->removePaths(watcher->files()); }
+ watcher->addPath(file.filePath); //make sure to update this shortcut if the file changes
+ }
+ }else if(ok){
+ QFileInfo info(path);
+ button->setWhatsThis(info.absoluteFilePath());
+ if(info.isDir()){
+ button->setIcon( LXDG::findIcon("folder","") );
+ }else if(LUtils::imageExtensions().contains(info.suffix().toLower()) ){
+ button->setIcon( QIcon(QPixmap(path).scaled(256,256)) ); //max size for thumbnails in memory
+ }else{
+ button->setIcon( QIcon(LXDG::findMimeIcon(path).pixmap(QSize(icosize,icosize)).scaledToHeight(icosize, Qt::SmoothTransformation) ) );
+ }
+ txt = info.fileName();
+ if(!watcher->files().isEmpty()){ watcher->removePaths(watcher->files()); }
+ watcher->addPath(path); //make sure to update this shortcut if the file changes
+ }else{
+ //InValid File
+ button->setWhatsThis("");
+ button->setIcon( QIcon(LXDG::findIcon("quickopen","").pixmap(QSize(icosize,icosize)).scaledToHeight(icosize, Qt::SmoothTransformation) ) );
+ button->setText( tr("Click to Set") );
+ if(!watcher->files().isEmpty()){ watcher->removePaths(watcher->files()); }
+ }
+ //If the file is a symlink, put the overlay on the icon
+ if(QFileInfo(path).isSymLink()){
+ QImage img = button->icon().pixmap(QSize(icosize,icosize)).toImage();
+ int oSize = icosize/3; //overlay size
+ QPixmap overlay = LXDG::findIcon("emblem-symbolic-link").pixmap(oSize,oSize).scaled(oSize,oSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ QPainter painter(&img);
+ painter.drawPixmap(icosize-oSize,icosize-oSize,overlay); //put it in the bottom-right corner
+ button->setIcon( QIcon(QPixmap::fromImage(img)) );
+ }
+ //Now adjust the visible text as necessary based on font/grid sizing
+ button->setToolTip(txt);
+ //Double check that the visual icon size matches the requested size - otherwise upscale the icon
+ if(button->fontMetrics().width(txt) > (button->width()-OUTMARGIN) ){
+ //Text too long, try to show it on two lines
+ //txt = button->fontMetrics().elidedText(txt, Qt::ElideRight, 2*(button->width()-OUTMARGIN), Qt::TextWordWrap);
+ txt =txt.section(" ",0,2).replace(" ","\n"); //First take care of any natural breaks
+ //Go through and combine any lines
+ if(txt.contains("\n")){
+ //need to check each line
+ QStringList txtL = txt.split("\n");
+ for(int i=0; i<txtL.length(); i++){
+ if(( i+1<txtL.length()) && (button->fontMetrics().width(txtL[i]) < button->width()/2) ){
+ txtL[i] = txtL[i]+" "+txtL[i+1];
+ txtL.removeAt(i+1);
+ }
+ }
+ txt = txtL.join("\n").section("\n",0,2);
+ }
+
+ if(txt.contains("\n")){
+ //need to check each line
+ QStringList txtL = txt.split("\n");
+ for(int i=0; i<txtL.length(); i++){
+ if(i>1){ txtL.removeAt(i); i--; } //Only take the first two lines
+ else{ txtL[i] = button->fontMetrics().elidedText(txtL[i], Qt::ElideRight, (button->width()-OUTMARGIN) ); }
+ }
+ txt = txtL.join("\n");
+ }else{
+ txt = this->fontMetrics().elidedText(txt,Qt::ElideRight, 2*(button->width()-OUTMARGIN));
+ //Now split the line in half for the two lines
+ txt.insert( ((txt.count())/2), "\n");
+ }
+ }
+ if(!txt.contains("\n")){ txt.append("\n "); } //always use two lines
+ //qDebug() << " - Setting Button Text:" << txt;
+ button->setText(txt);
+
+ QTimer::singleShot(100, this, SLOT(update()) ); //Make sure to re-draw the image in a moment
+}
+
+void AppLauncherPlugin::buttonClicked(){
+ QString path = button->whatsThis();
+ if(path.isEmpty() || !QFile::exists(path) ){
+ //prompt for the user to select an application
+ QList<XDGDesktop> apps = LXDG::sortDesktopNames( LXDG::systemDesktopFiles() );
+ QStringList names;
+ for(int i=0; i<apps.length(); i++){ names << apps[i].name; }
+ bool ok = false;
+ QString app = QInputDialog::getItem(this, tr("Select Application"), tr("Name:"), names, 0, false, &ok);
+ if(!ok || names.indexOf(app)<0){ return; } //cancelled
+ this->saveSetting("applicationpath", apps[ names.indexOf(app) ].filePath);
+ QTimer::singleShot(0,this, SLOT(loadButton()));
+ }else{
+ LSession::LaunchApplication("lumina-open \""+path+"\"");
+ }
+
+} \ No newline at end of file
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/applauncher/AppLauncherPlugin.h b/src-qt5/core/lumina-desktop/desktop-plugins/applauncher/AppLauncherPlugin.h
new file mode 100644
index 00000000..a0f6a7cd
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/applauncher/AppLauncherPlugin.h
@@ -0,0 +1,59 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This class is a quick sample desktop plugin
+//===========================================
+#ifndef _LUMINA_DESKTOP_DESKTOP_PLUGIN_APPLICATION_LAUNCHER_H
+#define _LUMINA_DESKTOP_DESKTOP_PLUGIN_APPLICATION_LAUNCHER_H
+
+#include <QToolButton>
+#include <QInputDialog>
+#include <QVBoxLayout>
+#include <QProcess>
+#include <QFile>
+#include <QFileSystemWatcher>
+#include <QTimer>
+#include <QMenu>
+#include <QCursor>
+
+#include "../LDPlugin.h"
+
+#include <LuminaXDG.h>
+
+class AppLauncherPlugin : public LDPlugin{
+ Q_OBJECT
+public:
+ AppLauncherPlugin(QWidget* parent, QString ID);
+ ~AppLauncherPlugin(){}
+
+ void Cleanup(); //special function for final cleanup
+
+private:
+ QToolButton *button;
+ QFileSystemWatcher *watcher;
+ //QMenu *menu;
+
+private slots:
+ void loadButton();
+ void buttonClicked();
+ //void openContextMenu();
+
+ //void increaseIconSize();
+ //void decreaseIconSize();
+ //void deleteFile();
+
+public slots:
+ void LocaleChange(){
+ loadButton(); //force reload
+ }
+
+protected:
+ void resizeEvent(QResizeEvent *ev){
+ LDPlugin::resizeEvent(ev);
+ QTimer::singleShot(100, this, SLOT(loadButton()) );
+ }
+};
+#endif
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/applauncher/OutlineToolButton.h b/src-qt5/core/lumina-desktop/desktop-plugins/applauncher/OutlineToolButton.h
new file mode 100644
index 00000000..eaf9e23e
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/applauncher/OutlineToolButton.h
@@ -0,0 +1,98 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This is a simple subclass for a QToolButton with black/white text (for transparent backgrounds)
+//===========================================
+#ifndef _LUMINA_DESKTOP_PLUGIN_APPLAUNCHER_OUTLINE_TOOLBUTTON_H
+#define _LUMINA_DESKTOP_PLUGIN_APPLAUNCHER_OUTLINE_TOOLBUTTON_H
+
+#include <QToolButton>
+#include <QPainter>
+#include <QPainterPath>
+#include <QPen>
+#include <QStyle>
+#include <QStyleOption>
+#include <QStylePainter>
+#include <QFont>
+#include <QDebug>
+#include <QMouseEvent>
+
+
+class OutlineToolButton : public QToolButton{
+ Q_OBJECT
+public:
+ OutlineToolButton(QWidget *parent=0) : QToolButton(parent){
+ //This button needs slightly different font settings - do this in the constructor so that other widgets can take it into account.
+ QFont font = this->font();
+ font.setStyleStrategy(QFont::PreferAntialias); //Always set the font strategy (just in case it starts working down the road)
+ this->setFont(font);
+ }
+ ~OutlineToolButton(){}
+
+signals:
+ void DoubleClicked();
+
+protected:
+ void mouseDoubleClickEvent(QMouseEvent *ev){
+ ev->accept();
+ emit DoubleClicked();
+ }
+ void mousePressEvent(QMouseEvent *ev){
+ ev->ignore();
+ }
+ void mouseReleaseEvent(QMouseEvent *ev){
+ ev->ignore();
+ }
+
+ void paintEvent(QPaintEvent*){
+ /* NOTE: This is what a standard QToolButton performs (peeked at Qt source code for this tidbit)
+ QStylePainter p(this);
+ QStyleOptionToolButton opt;
+ initStyleOption(&opt);
+ p.drawComplexControl(QStyle::CC_ToolButton, opt);
+ */
+
+ //Modify the standard QToolButton routine to paint the text differently
+ QStylePainter p(this);
+ QStyleOptionToolButton opt;
+ initStyleOption(&opt);
+ opt.font = this->property("font").value<QFont>(); //This ensures that the stylesheet values are incorporated
+ opt.font.setStyleStrategy(QFont::PreferAntialias); //Always set the font strategy (just in case it starts working down the road)
+ opt.font.setKerning(true);
+ opt.fontMetrics = QFontMetrics(opt.font);
+ opt.text.clear(); //Don't paint the text yet - just the background/icon
+ p.drawComplexControl(QStyle::CC_ToolButton, opt); //This does all the normal QToolButton stuff - just not text
+ //Now get the text rectangle for the widget
+ QRect box = p.style()->itemTextRect(opt.fontMetrics, opt.rect, Qt::AlignHCenter | Qt::AlignBottom, true, this->text());
+ //Get the QColors for the outline/text
+ QColor textC = opt.palette.text().color().toHsl(); //need the lightness value in a moment
+ QColor outC = textC;
+ //qDebug() << "Font Color Values:" << textC << textC.lightness() << textC.lightnessF();
+ if(textC.lightnessF() > 0.5){ outC.setHsl(textC.hue(), textC.hslSaturation(), 0, 90); }
+ else{outC.setHsl(textC.hue(), textC.hslSaturation(), 255, 50); }
+ //qDebug() << "Outline Color Values:" << outC;
+ //Now get the size of the outline border (need to scale for high-res monitors)
+ qreal OWidth = opt.fontMetrics.width("o")/2.0;
+ //qDebug() << "Outline Width:" << OWidth;
+ //Now generate a QPainterPath for the text
+ QPainterPath path;
+ QStringList txt = this->text().split("\n"); //need each line independently, the newline actually gets painted otherwise
+ for(int i=0; i<txt.length(); i++){
+ path.addText(box.center().x() - (opt.fontMetrics.width(txt[i])/2), box.y()+((i+1)*(box.height()/txt.length()))-opt.fontMetrics.descent(), opt.font, txt[i] );
+ }
+ path.setFillRule(Qt::WindingFill);
+ //Now paint the text
+ QRadialGradient RG(box.center(), box.width()*1.5); //width is always going to be greater than height
+ RG.setColorAt(0, outC);
+ RG.setColorAt(1, Qt::transparent);
+ p.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); //need antialiasing for this to work well (sub-pixel painting)
+ p.strokePath(path, QPen(QBrush(RG),OWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin) ); //This will be the outline - 1pixel thick, semi-transparent
+ p.fillPath(path, QBrush(textC)); //this will be the inside/text color
+
+ }
+
+};
+#endif
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/audioplayer/PlayerWidget.cpp b/src-qt5/core/lumina-desktop/desktop-plugins/audioplayer/PlayerWidget.cpp
new file mode 100644
index 00000000..4d293b39
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/audioplayer/PlayerWidget.cpp
@@ -0,0 +1,269 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "PlayerWidget.h"
+#include "ui_PlayerWidget.h"
+
+#include <QDir>
+#include <QUrl>
+#include <QInputDialog>
+#include <QFileDialog>
+#include <LuminaXDG.h>
+#include <QDebug>
+#include <QDesktopWidget>
+
+PlayerWidget::PlayerWidget(QWidget *parent) : QWidget(parent), ui(new Ui::PlayerWidget()){
+ ui->setupUi(this); //load the designer form
+ PLAYER = new QMediaPlayer(this);
+ PLAYER->setVolume(100);
+ PLAYER->setNotifyInterval(1000); //1 second interval (just needs to be a rough estimate)
+ PLAYLIST = new QMediaPlaylist(this);
+ PLAYLIST->setPlaybackMode(QMediaPlaylist::Sequential);
+ PLAYER->setPlaylist(PLAYLIST);
+
+ configMenu = new QMenu(this);
+ ui->tool_config->setMenu(configMenu);
+ addMenu = new QMenu(this);
+ ui->tool_add->setMenu(addMenu);
+
+ updatinglists = false; //start off as false
+
+ LoadIcons();
+ playerStateChanged(); //update button visibility
+ currentSongChanged();
+ //Connect all the signals/slots
+ //connect(infoTimer, SIGNAL(timeout()), this, SLOT(rotateTrackInfo()) );
+ connect(PLAYER, SIGNAL(positionChanged(qint64)),this, SLOT(updateProgress(qint64)) );
+ connect(PLAYER, SIGNAL(durationChanged(qint64)), this, SLOT(updateMaxProgress(qint64)) );
+ connect(PLAYLIST, SIGNAL(mediaChanged(int, int)), this, SLOT(playlistChanged()) );
+ connect(PLAYER, SIGNAL(stateChanged(QMediaPlayer::State)), this, SLOT(playerStateChanged()) );
+ connect(PLAYLIST, SIGNAL(currentMediaChanged(const QMediaContent&)), this, SLOT(currentSongChanged()) );
+ connect(ui->combo_playlist, SIGNAL(currentIndexChanged(int)), this, SLOT(userlistSelectionChanged()) );
+ connect(ui->tool_play, SIGNAL(clicked()), this, SLOT(playClicked()) );
+ connect(ui->tool_pause, SIGNAL(clicked()), this, SLOT(pauseClicked()) );
+ connect(ui->tool_stop, SIGNAL(clicked()), this, SLOT(stopClicked()) );
+ connect(ui->tool_next, SIGNAL(clicked()), this, SLOT(nextClicked()) );
+ connect(ui->tool_prev, SIGNAL(clicked()), this, SLOT(prevClicked()) );
+
+}
+
+PlayerWidget::~PlayerWidget(){
+ //qDebug() << "Removing PlayerWidget";
+}
+
+void PlayerWidget::LoadIcons(){
+ ui->tool_stop->setIcon( LXDG::findIcon("media-playback-stop","") );
+ ui->tool_play->setIcon( LXDG::findIcon("media-playback-start","") );
+ ui->tool_pause->setIcon( LXDG::findIcon("media-playback-pause","") );
+ ui->tool_next->setIcon( LXDG::findIcon("media-skip-forward","") );
+ ui->tool_prev->setIcon( LXDG::findIcon("media-skip-backward","") );
+ ui->tool_add->setIcon( LXDG::findIcon("list-add","") );
+ ui->tool_config->setIcon( LXDG::findIcon("configure","") );
+ //Now re-assemble the menus as well
+ configMenu->clear();
+ configMenu->addAction(LXDG::findIcon("media-eject",""), tr("Clear Playlist"), this, SLOT(ClearPlaylist()));
+ configMenu->addAction(LXDG::findIcon("roll",""), tr("Shuffle Playlist"), this, SLOT(ShufflePlaylist()));
+ addMenu->clear();
+ addMenu->addAction(LXDG::findIcon("document-new",""), tr("Add Files"), this, SLOT(AddFilesToPlaylist()));
+ addMenu->addAction(LXDG::findIcon("folder-new",""), tr("Add Directory"), this, SLOT(AddDirToPlaylist()));
+ addMenu->addAction(LXDG::findIcon("download",""), tr("Add URL"), this, SLOT(AddURLToPlaylist()));
+}
+
+void PlayerWidget::playClicked(){
+ PLAYER->play();
+}
+
+void PlayerWidget::pauseClicked(){
+ PLAYER->pause();
+}
+
+void PlayerWidget::stopClicked(){
+ PLAYER->stop();
+}
+
+void PlayerWidget::nextClicked(){
+ PLAYLIST->next();
+}
+
+void PlayerWidget::prevClicked(){
+ PLAYLIST->previous();
+}
+
+void PlayerWidget::AddFilesToPlaylist(){
+ //Prompt the user to select multimedia files
+ QFileDialog dlg(0, Qt::Dialog | Qt::WindowStaysOnTopHint );
+ dlg.setFileMode(QFileDialog::ExistingFiles);
+ dlg.setAcceptMode(QFileDialog::AcceptOpen);
+ dlg.setNameFilter( tr("Multimedia Files")+" ("+LXDG::findAVFileExtensions().join(" ")+")");
+ dlg.setWindowTitle(tr("Select Multimedia Files"));
+ dlg.setWindowIcon( LXDG::findIcon("file-open","") );
+ dlg.setDirectory(QDir::homePath()); //start in the home directory
+ //ensure it is centered on the current screen
+ QPoint center = QApplication::desktop()->screenGeometry(this).center();
+ dlg.move( center.x()-(dlg.width()/2), center.y()-(dlg.height()/2) );
+ dlg.show();
+ while( dlg.isVisible() ){
+ QApplication::processEvents();
+ }
+ QList<QUrl> files = dlg.selectedUrls();
+ if(files.isEmpty() || dlg.result()!=QDialog::Accepted){ return; } //cancelled
+ //Make this use show/processEvents later
+ //QList<QUrl> files = QFileDialog::getOpenFileUrls(0, tr("Select Multimedia Files"), QDir::homePath(), "Multimedia Files ("+LXDG::findAVFileExtensions().join(" ")+")");
+ QList<QMediaContent> urls;
+ for(int i=0; i<files.length(); i++){
+ urls << QMediaContent(files[i]);
+ }
+ PLAYLIST->addMedia(urls);
+ playlistChanged();
+}
+
+void PlayerWidget::AddDirToPlaylist(){
+ QFileDialog dlg(0, Qt::Dialog | Qt::WindowStaysOnTopHint );
+ dlg.setFileMode(QFileDialog::Directory);
+ dlg.setOption(QFileDialog::ShowDirsOnly, true);
+ dlg.setAcceptMode(QFileDialog::AcceptOpen);
+ dlg.setWindowTitle(tr("Select Multimedia Directory"));
+ dlg.setWindowIcon( LXDG::findIcon("folder-open","") );
+ dlg.setDirectory(QDir::homePath()); //start in the home directory
+ //ensure it is centered on the current screen
+ QPoint center = QApplication::desktop()->screenGeometry(this).center();
+ dlg.move( center.x()-(dlg.width()/2), center.y()-(dlg.height()/2) );
+ dlg.show();
+ while( dlg.isVisible() ){
+ QApplication::processEvents();
+ }
+ if(dlg.result() != QDialog::Accepted){ return; } //cancelled
+ QStringList sel = dlg.selectedFiles();
+ if(sel.isEmpty()){ return; } //cancelled
+ QString dirpath = sel.first(); //QFileDialog::getExistingDirectory(0, tr("Select a Multimedia Directory"), QDir::homePath() );
+ if(dirpath.isEmpty()){ return; } //cancelled
+ QDir dir(dirpath);
+ QFileInfoList files = dir.entryInfoList(LXDG::findAVFileExtensions(), QDir::Files | QDir::NoDotAndDotDot, QDir::Name);
+ if(files.isEmpty()){ return; } //nothing in this directory
+ QList<QMediaContent> urls;
+ for(int i=0; i<files.length(); i++){
+ urls << QMediaContent(QUrl::fromLocalFile(files[i].absoluteFilePath()) );
+ }
+ PLAYLIST->addMedia(urls);
+ playlistChanged();
+}
+
+void PlayerWidget::AddURLToPlaylist(){
+ QInputDialog dlg(0, Qt::Dialog | Qt::WindowStaysOnTopHint );
+ dlg.setInputMode(QInputDialog::TextInput);
+ dlg.setLabelText(tr("Enter a valid URL for a multimedia file or stream:"));
+ dlg.setTextEchoMode(QLineEdit::Normal);
+ dlg.setWindowTitle(tr("Multimedia URL"));
+ dlg.setWindowIcon( LXDG::findIcon("download","") );
+ //ensure it is centered on the current screen
+ QPoint center = QApplication::desktop()->screenGeometry(this).center();
+ dlg.move( center.x()-(dlg.width()/2), center.y()-(dlg.height()/2) );
+ dlg.show();
+ while( dlg.isVisible() ){
+ QApplication::processEvents();
+ }
+ QString url = dlg.textValue();
+ if(url.isEmpty() || dlg.result()!=QDialog::Accepted){ return; } //cancelled
+
+ //QString url = QInputDialog::getText(0, tr("Multimedia URL"), tr("Enter a valid URL for a multimedia file or stream"), QLineEdit::Normal);
+ //if(url.isEmpty()){ return; }
+ QUrl newurl(url);
+ if(!newurl.isValid()){ return; } //invalid URL
+ PLAYLIST->addMedia(newurl);
+ playlistChanged();
+}
+
+void PlayerWidget::ClearPlaylist(){
+ PLAYER->stop();
+ PLAYLIST->clear();
+ playlistChanged();
+}
+
+void PlayerWidget::ShufflePlaylist(){
+ PLAYLIST->shuffle();
+}
+
+
+void PlayerWidget::userlistSelectionChanged(){ //front-end combobox was changed by the user
+ if(updatinglists){ return; }
+ PLAYLIST->setCurrentIndex( ui->combo_playlist->currentIndex() );
+}
+
+void PlayerWidget::playerStateChanged(){
+ switch( PLAYER->state() ){
+ case QMediaPlayer::StoppedState:
+ ui->tool_stop->setVisible(false);
+ ui->tool_play->setVisible(true);
+ ui->tool_pause->setVisible(false);
+ ui->progressBar->setVisible(false);
+ break;
+ case QMediaPlayer::PausedState:
+ ui->tool_stop->setVisible(true);
+ ui->tool_play->setVisible(true);
+ ui->tool_pause->setVisible(false);
+ ui->progressBar->setVisible(true);
+ break;
+ case QMediaPlayer::PlayingState:
+ ui->tool_stop->setVisible(true);
+ ui->tool_play->setVisible(false);
+ ui->tool_pause->setVisible(true);
+ ui->progressBar->setVisible(true);
+ break;
+ }
+
+}
+
+void PlayerWidget::playlistChanged(){
+ updatinglists = true;
+ ui->combo_playlist->clear();
+ for(int i=0; i<PLAYLIST->mediaCount(); i++){
+ QUrl url = PLAYLIST->media(i).canonicalUrl();
+ if(url.isLocalFile()){
+ ui->combo_playlist->addItem(LXDG::findMimeIcon(url.fileName().section(".",-1)), url.fileName() );
+ }else{
+ ui->combo_playlist->addItem(LXDG::findIcon("download",""), url.toString() );
+ }
+ }
+ if(PLAYLIST->currentIndex()<0 && PLAYLIST->mediaCount()>0){ PLAYLIST->setCurrentIndex(0); }
+ ui->combo_playlist->setCurrentIndex(PLAYLIST->currentIndex());
+
+ updatinglists = false;
+}
+
+void PlayerWidget::currentSongChanged(){
+ if(PLAYLIST->currentIndex() != ui->combo_playlist->currentIndex()){
+ updatinglists = true;
+ ui->combo_playlist->setCurrentIndex(PLAYLIST->currentIndex());
+ updatinglists = false;
+ }
+ ui->tool_next->setEnabled( PLAYLIST->nextIndex() >= 0 );
+ ui->tool_prev->setEnabled( PLAYLIST->previousIndex() >= 0);
+ ui->label_num->setText( QString::number( PLAYLIST->currentIndex()+1)+"/"+QString::number(PLAYLIST->mediaCount()) );
+ ui->progressBar->setRange(0, PLAYER->duration() );
+ ui->progressBar->setValue(0);
+}
+
+void PlayerWidget::updateProgress(qint64 val){
+ //qDebug() << "Update Progress Bar:" << val;
+ ui->progressBar->setValue(val);
+}
+
+void PlayerWidget::updateMaxProgress(qint64 val){
+ ui->progressBar->setRange(0,val);
+}
+
+
+AudioPlayerPlugin::AudioPlayerPlugin(QWidget *parent, QString ID) : LDPlugin(parent, ID){
+ player = new PlayerWidget(this);
+ this->setLayout( new QVBoxLayout() );
+ this->layout()->setContentsMargins(0,0,0,0);
+ this->layout()->addWidget(player);
+
+}
+
+AudioPlayerPlugin::~AudioPlayerPlugin(){
+ //qDebug() << "Remove AudioPlayerPlugin";
+} \ No newline at end of file
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/audioplayer/PlayerWidget.h b/src-qt5/core/lumina-desktop/desktop-plugins/audioplayer/PlayerWidget.h
new file mode 100644
index 00000000..6aaeac4c
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/audioplayer/PlayerWidget.h
@@ -0,0 +1,84 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This plugin is a simple audio player on the desktop
+//===========================================
+#ifndef _LUMINA_DESKTOP_PLUGIN_AUDIO_PLAYER_WIDGET_H
+#define _LUMINA_DESKTOP_PLUGIN_AUDIO_PLAYER_WIDGET_H
+
+#include <QMediaPlaylist>
+#include <QMediaPlayer>
+#include <QTimer>
+#include <QWidget>
+#include <QMenu>
+
+#include "../LDPlugin.h"
+
+namespace Ui{
+ class PlayerWidget;
+};
+
+class PlayerWidget : public QWidget{
+ Q_OBJECT
+public:
+ PlayerWidget(QWidget *parent = 0);
+ ~PlayerWidget();
+
+public slots:
+ void LoadIcons();
+
+private:
+ Ui::PlayerWidget *ui;
+ QMediaPlaylist *PLAYLIST;
+ QMediaPlayer *PLAYER;
+ QMenu *configMenu, *addMenu;
+ bool updatinglists;
+
+private slots:
+ void playClicked();
+ void pauseClicked();
+ void stopClicked();
+ void nextClicked();
+ void prevClicked();
+
+ void AddFilesToPlaylist();
+ void AddDirToPlaylist();
+ void AddURLToPlaylist();
+ void ClearPlaylist();
+ void ShufflePlaylist();
+ void userlistSelectionChanged(); //front-end combobox was changed by the user
+ void playerStateChanged();
+ void playlistChanged(); //list of items changed
+ void currentSongChanged();
+ void updateProgress(qint64 val);
+ void updateMaxProgress(qint64 val);
+};
+
+// Wrapper class to put this into a desktop plugin container
+class AudioPlayerPlugin : public LDPlugin{
+ Q_OBJECT
+public:
+ AudioPlayerPlugin(QWidget* parent, QString ID);
+ ~AudioPlayerPlugin();
+
+ virtual QSize defaultPluginSize(){
+ // The returned QSize is in grid points (typically 100 or 200 pixels square)
+ return QSize(3,1);
+ }
+
+private:
+ PlayerWidget *player;
+
+public slots:
+ void LocaleChange(){
+ QTimer::singleShot(0,player, SLOT(LoadIcons()));
+ }
+ void ThemeChange(){
+ QTimer::singleShot(0,player, SLOT(LoadIcons()));
+ }
+};
+
+#endif
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/audioplayer/PlayerWidget.ui b/src-qt5/core/lumina-desktop/desktop-plugins/audioplayer/PlayerWidget.ui
new file mode 100644
index 00000000..b1e7ee59
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/audioplayer/PlayerWidget.ui
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PlayerWidget</class>
+ <widget class="QWidget" name="PlayerWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>346</width>
+ <height>81</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QToolButton::menu-indicator{ image: none; }</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <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_2">
+ <item>
+ <widget class="QToolButton" name="tool_config">
+ <property name="text">
+ <string notr="true">Config</string>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_add">
+ <property name="text">
+ <string notr="true">Add</string>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <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="QToolButton" name="tool_prev">
+ <property name="text">
+ <string notr="true">prev</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_num">
+ <property name="text">
+ <string notr="true">1/10</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_next">
+ <property name="text">
+ <string notr="true">next</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QComboBox" name="combo_playlist"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QToolButton" name="tool_play">
+ <property name="text">
+ <string notr="true">Play</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_pause">
+ <property name="text">
+ <string notr="true">Pause</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_stop">
+ <property name="text">
+ <string notr="true">Stop</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </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>
+ <item>
+ <widget class="QProgressBar" name="progressBar">
+ <property name="value">
+ <number>24</number>
+ </property>
+ <property name="textVisible">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/calendar/CalendarPlugin.h b/src-qt5/core/lumina-desktop/desktop-plugins/calendar/CalendarPlugin.h
new file mode 100644
index 00000000..b3a6a8d7
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/calendar/CalendarPlugin.h
@@ -0,0 +1,58 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This class is a quick sample desktop plugin
+//===========================================
+#ifndef _LUMINA_DESKTOP_DESKTOP_PLUGIN_CALENDAR_H
+#define _LUMINA_DESKTOP_DESKTOP_PLUGIN_CALENDAR_H
+
+#include <QCalendarWidget>
+#include <QVBoxLayout>
+#include <QDate>
+#include <QTimer>
+#include "../LDPlugin.h"
+
+class CalendarPlugin : public LDPlugin{
+ Q_OBJECT
+private:
+ QCalendarWidget *cal;
+ QTimer *timer;
+
+public:
+ CalendarPlugin(QWidget* parent, QString ID) : LDPlugin(parent, ID){
+ this->setLayout( new QVBoxLayout());
+ this->layout()->setContentsMargins(0,0,0,0);
+ cal = new QCalendarWidget(this);
+ cal->setSelectionMode(QCalendarWidget::NoSelection);
+ this->layout()->addWidget(cal);
+ timer = new QTimer(this);
+ timer->setInterval(1800000); //30 minute refresh timer
+ timer->start();
+ QTimer::singleShot(0,this, SLOT(updateDate()) );
+ connect(this, SIGNAL(PluginResized()), this, SLOT(UpdateCalendarSize()));
+ }
+
+ ~CalendarPlugin(){ timer->stop(); }
+
+ virtual QSize defaultPluginSize(){
+ // The returned QSize is in grid points (typically 100 or 200 pixels square)
+ return QSize(3,2);
+ }
+
+private slots:
+ void updateDate(){
+ if(cal->selectedDate() != QDate::currentDate()){
+ cal->setSelectedDate(QDate::currentDate());
+ cal->showSelectedDate();
+ }
+ }
+ void UpdateCalendarSize(){
+ cal->setFixedSize(this->size());
+ }
+
+
+};
+#endif
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/desktop-plugins.pri b/src-qt5/core/lumina-desktop/desktop-plugins/desktop-plugins.pri
new file mode 100644
index 00000000..5a631b52
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/desktop-plugins.pri
@@ -0,0 +1,19 @@
+SOURCES += $$PWD/applauncher/AppLauncherPlugin.cpp \
+ $$PWD/desktopview/DesktopViewPlugin.cpp \
+ $$PWD/notepad/NotepadPlugin.cpp \
+ $$PWD/audioplayer/PlayerWidget.cpp \
+ $$PWD/systemmonitor/MonitorWidget.cpp
+# $$PWD/messagecenter/MessageCenter.cpp
+
+HEADERS += $$PWD/calendar/CalendarPlugin.h \
+ $$PWD/applauncher/AppLauncherPlugin.h \
+ $$PWD/applauncher/OutlineToolButton.h \
+ $$PWD/desktopview/DesktopViewPlugin.h \
+ $$PWD/notepad/NotepadPlugin.h \
+ $$PWD/audioplayer/PlayerWidget.h \
+ $$PWD/systemmonitor/MonitorWidget.h
+# $$PWD/quickcontainer/QuickDPlugin.h
+# $$PWD/messagecenter/MessageCenter.h
+
+FORMS += $$PWD/audioplayer/PlayerWidget.ui \
+ $$PWD/systemmonitor/MonitorWidget.ui \ No newline at end of file
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/desktopview/DesktopViewPlugin.cpp b/src-qt5/core/lumina-desktop/desktop-plugins/desktopview/DesktopViewPlugin.cpp
new file mode 100644
index 00000000..01e174e9
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/desktopview/DesktopViewPlugin.cpp
@@ -0,0 +1,215 @@
+#include "DesktopViewPlugin.h"
+
+#include <QFileInfo>
+#include <QDir>
+#include <QClipboard>
+#include <QMimeData>
+#include <QImageReader>
+
+#include <LuminaXDG.h>
+#include "LSession.h"
+
+
+DesktopViewPlugin::DesktopViewPlugin(QWidget* parent, QString ID) : LDPlugin(parent, ID){
+ this->setLayout( new QVBoxLayout());
+ this->layout()->setContentsMargins(0,0,0,0);
+
+ list = new QListWidget(this);
+ list->setViewMode(QListView::IconMode);
+ list->setFlow(QListWidget::TopToBottom); //Qt bug workaround - need the opposite flow in the widget constructor
+ list->setWrapping(true);
+ list->setSpacing(4);
+ list->setSelectionBehavior(QAbstractItemView::SelectItems);
+ list->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ list->setContextMenuPolicy(Qt::CustomContextMenu);
+ list->setMovement(QListView::Snap); //make sure items are "stuck" in the grid
+
+ menu = new QMenu(this);
+ menu->addAction( LXDG::findIcon("run-build-file",""), tr("Open"), this, SLOT(runItems()) );
+ menu->addSeparator();
+ menu->addAction( LXDG::findIcon("edit-cut",""), tr("Cut"), this, SLOT(cutItems()) );
+ menu->addAction( LXDG::findIcon("edit-copy",""), tr("Copy"), this, SLOT(copyItems()) );
+ menu->addSeparator();
+ menu->addAction( LXDG::findIcon("zoom-in",""), tr("Increase Icons"), this, SLOT(increaseIconSize()) );
+ menu->addAction( LXDG::findIcon("zoom-out",""), tr("Decrease Icons"), this, SLOT(decreaseIconSize()) );
+ menu->addSeparator();
+ menu->addAction( LXDG::findIcon("edit-delete",""), tr("Delete"), this, SLOT(deleteItems()) );
+ menu->addSeparator();
+ if(LUtils::isValidBinary("lumina-fileinfo")){
+ menu->addAction( LXDG::findIcon("system-search",""), tr("Properties"), this, SLOT(displayProperties()) );
+ }
+ this->layout()->addWidget(list);
+
+ connect(QApplication::instance(), SIGNAL(DesktopFilesChanged()), this, SLOT(updateContents()) );
+ connect(list, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(runItems()) );
+ connect(list, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showMenu(const QPoint&)) );
+ QTimer::singleShot(1000,this, SLOT(updateContents()) ); //wait a second before loading contents
+}
+
+DesktopViewPlugin::~DesktopViewPlugin(){
+
+}
+
+void DesktopViewPlugin::runItems(){
+ QList<QListWidgetItem*> sel = list->selectedItems();
+ for(int i=0; i<sel.length(); i++){
+ LSession::LaunchApplication("lumina-open \""+sel[i]->whatsThis()+"\"");
+ }
+}
+
+void DesktopViewPlugin::copyItems(){
+ QList<QListWidgetItem*> sel = list->selectedItems();
+ if(sel.isEmpty()){ return; } //nothing selected
+ QStringList items;
+ //Format the data string
+ for(int i=0; i<sel.length(); i++){
+ items << "copy::::"+sel[i]->whatsThis();
+ }
+ //Now save that data to the global clipboard
+ QMimeData *dat = new QMimeData;
+ dat->clear();
+ dat->setData("x-special/lumina-copied-files", items.join("\n").toLocal8Bit());
+ QApplication::clipboard()->clear();
+ QApplication::clipboard()->setMimeData(dat);
+}
+
+void DesktopViewPlugin::cutItems(){
+ QList<QListWidgetItem*> sel = list->selectedItems();
+ if(sel.isEmpty()){ return; } //nothing selected
+ QStringList items;
+ //Format the data string
+ for(int i=0; i<sel.length(); i++){
+ items << "cut::::"+sel[i]->whatsThis();
+ }
+ //Now save that data to the global clipboard
+ QMimeData *dat = new QMimeData;
+ dat->clear();
+ dat->setData("x-special/lumina-copied-files", items.join("\n").toLocal8Bit());
+ QApplication::clipboard()->clear();
+ QApplication::clipboard()->setMimeData(dat);
+}
+
+void DesktopViewPlugin::deleteItems(){
+ QList<QListWidgetItem*> sel = list->selectedItems();
+ for(int i=0; i<sel.length(); i++){
+ if(QFileInfo(sel[i]->whatsThis()).isDir()){
+ QProcess::startDetached("rm -r \""+sel[i]->whatsThis()+"\"");
+ }else{
+ QFile::remove(sel[i]->whatsThis());
+ }
+ }
+}
+
+void DesktopViewPlugin::showMenu(const QPoint &pos){
+ //Make sure there is an item underneath the mouse first
+ if(list->itemAt(pos)!=0){
+ menu->popup(this->mapToGlobal(pos));
+ }else{
+ //Pass the context menu request on to the desktop (emit it from the plugin)
+ this->showPluginMenu();
+ //emit OpenDesktopMenu();
+ }
+}
+
+void DesktopViewPlugin::increaseIconSize(){
+ int icosize = this->readSetting("IconSize",64).toInt();
+ icosize+=16; //go in orders of 16 pixels
+ //list->setIconSize(QSize(icosize,icosize));
+ this->saveSetting("IconSize",icosize);
+ QTimer::singleShot(10, this, SLOT(updateContents()));
+}
+
+void DesktopViewPlugin::decreaseIconSize(){
+ int icosize = this->readSetting("IconSize",64).toInt();
+ if(icosize < 20){ return; } //too small to decrease more
+ icosize-=16; //go in orders of 16 pixels
+ //list->setIconSize(QSize(icosize,icosize));
+ this->saveSetting("IconSize",icosize);
+ QTimer::singleShot(10,this, SLOT(updateContents()));
+}
+
+void DesktopViewPlugin::updateContents(){
+ list->clear();
+
+ int icosize = this->readSetting("IconSize",64).toInt();
+ QSize gridSZ = QSize(qRound(1.8*icosize),icosize+4+(2*this->fontMetrics().height()) );
+ //qDebug() << "Icon Size:" << icosize <<"Grid Size:" << gridSZ.width() << gridSZ.height();
+ list->setGridSize(gridSZ);
+ list->setIconSize(QSize(icosize,icosize));
+ QDir dir(QDir::homePath()+"/Desktop");
+ QFileInfoList files = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name | QDir::Type | QDir::DirsFirst);
+ for(int i=0; i<files.length(); i++){
+ QListWidgetItem *it = new QListWidgetItem;
+ it->setSizeHint(gridSZ); //ensure uniform item sizes
+ //it->setForeground(QBrush(Qt::black, Qt::Dense2Pattern)); //Try to use a font color which will always be visible
+ it->setTextAlignment(Qt::AlignCenter);
+ it->setWhatsThis(files[i].absoluteFilePath());
+ QString txt;
+ if(files[i].isDir()){
+ it->setIcon( LXDG::findIcon("folder","") );
+ txt = files[i].fileName();
+ }else if(files[i].suffix() == "desktop" ){
+ bool ok = false;
+ XDGDesktop desk = LXDG::loadDesktopFile(files[i].absoluteFilePath(), ok);
+ if(ok){
+ it->setIcon( LXDG::findIcon(desk.icon,"unknown") );
+ if(desk.name.isEmpty()){
+ txt = files[i].fileName();
+ }else{
+ txt = desk.name;
+ }
+ }else{
+ //Revert back to a standard file handling
+ it->setIcon( LXDG::findMimeIcon(files[i].fileName()) );
+ txt = files[i].fileName();
+ }
+ }else if(LUtils::imageExtensions().contains(files[i].suffix().toLower()) ){
+ it->setIcon( QIcon( QPixmap(files[i].absoluteFilePath()).scaled(icosize,icosize,Qt::IgnoreAspectRatio, Qt::SmoothTransformation) ) );
+ txt = files[i].fileName();
+ }else{
+ it->setIcon( LXDG::findMimeIcon( files[i].fileName() ) );
+ txt = files[i].fileName();
+ }
+ //Add the sym-link overlay to the icon as necessary
+ if(files[i].isSymLink()){
+ QImage img = it->icon().pixmap(QSize(icosize,icosize)).toImage();
+ int oSize = icosize/2; //overlay size
+ QPixmap overlay = LXDG::findIcon("emblem-symbolic-link").pixmap(oSize,oSize).scaled(oSize,oSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ QPainter painter(&img);
+ painter.drawPixmap(icosize-oSize,icosize-oSize,overlay); //put it in the bottom-right corner
+ it->setIcon( QIcon(QPixmap::fromImage(img)) );
+ }
+ //Now adjust the visible text as necessary based on font/grid sizing
+ it->setToolTip(txt);
+ if(this->fontMetrics().width(txt) > (gridSZ.width()-4) ){
+ //int dash = this->fontMetrics().width("-");
+ //Text too long, try to show it on two lines
+ txt = txt.section(" ",0,2).replace(" ","\n"); //First take care of any natural breaks
+ if(txt.contains("\n")){
+ //need to check each line
+ QStringList txtL = txt.split("\n");
+ for(int i=0; i<txtL.length(); i++){ txtL[i] = this->fontMetrics().elidedText(txtL[i], Qt::ElideRight, gridSZ.width()-4); }
+ txt = txtL.join("\n");
+ if(txtL.length()>2){ txt = txt.section("\n",0,1); } //only keep the first two lines
+ }else{
+ txt = this->fontMetrics().elidedText(txt,Qt::ElideRight, 2*(gridSZ.width()-4));
+ //Now split the line in half for the two lines
+ txt.insert( (txt.count()/2), "\n");
+ }
+ }else{
+ txt.append("\n "); //ensure two lines (2nd one invisible) - keeps formatting sane
+ }
+ it->setText(txt);
+ list->addItem(it);
+ if( (i%10) == 0){ QApplication::processEvents(); }//keep the UI snappy, every 10 items
+ }
+ list->setFlow(QListWidget::TopToBottom); //To ensure this is consistent - issues with putting it in the constructor
+ list->update(); //Re-paint the widget after all items are added
+}
+
+void DesktopViewPlugin::displayProperties(){
+ QList<QListWidgetItem*> sel = list->selectedItems();
+ for(int i=0; i<sel.length(); i++){
+ LSession::LaunchApplication("lumina-fileinfo \""+sel[i]->whatsThis());
+ }
+}
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/desktopview/DesktopViewPlugin.h b/src-qt5/core/lumina-desktop/desktop-plugins/desktopview/DesktopViewPlugin.h
new file mode 100644
index 00000000..046b6e5c
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/desktopview/DesktopViewPlugin.h
@@ -0,0 +1,55 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This plugin is a listing/launcher for things in the ~/Desktop folder
+//===========================================
+#ifndef _LUMINA_DESKTOP_DESKTOP_VIEW_PLUGIN_H
+#define _LUMINA_DESKTOP_DESKTOP_VIEW_PLUGIN_H
+
+#include <QListWidget>
+#include <QVBoxLayout>
+#include <QTimer>
+#include <QFileSystemWatcher>
+#include <QMouseEvent>
+
+#include "../LDPlugin.h"
+
+class DesktopViewPlugin : public LDPlugin{
+ Q_OBJECT
+public:
+ DesktopViewPlugin(QWidget* parent, QString ID);
+ ~DesktopViewPlugin();
+
+ virtual QSize defaultPluginSize(){
+ // The returned QSize is in grid points (typically 100 or 200 pixels square)
+ return QSize(3,3);
+ }
+private:
+ QListWidget *list;
+ QMenu *menu;
+
+private slots:
+ void runItems();
+ void copyItems();
+ void cutItems();
+ void deleteItems();
+ void showMenu(const QPoint&);
+ void increaseIconSize();
+ void decreaseIconSize();
+ void updateContents();
+ void displayProperties();
+
+
+public slots:
+ void LocaleChange(){
+ QTimer::singleShot(0,this, SLOT(updateContents()));
+ }
+ void ThemeChange(){
+ QTimer::singleShot(0,this, SLOT(updateContents()));
+ }
+
+};
+#endif
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/messagecenter/LXDG-DBusNotifier.h b/src-qt5/core/lumina-desktop/desktop-plugins/messagecenter/LXDG-DBusNotifier.h
new file mode 100644
index 00000000..64413e95
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/messagecenter/LXDG-DBusNotifier.h
@@ -0,0 +1,17 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// Simple DBUS message handler for the FreeDesktop desktop notifications specification
+
+
+class LXDG-DBusNotifier : public QDBusVirtualObkect{
+ Q_OBJECT
+public:
+
+private:
+
+
+};
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/messagecenter/MessageCenter.cpp b/src-qt5/core/lumina-desktop/desktop-plugins/messagecenter/MessageCenter.cpp
new file mode 100644
index 00000000..df07a122
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/messagecenter/MessageCenter.cpp
@@ -0,0 +1,90 @@
+#include "MessageCenter.h"
+
+#include <LuminaXDG.h>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QDBusConnection>
+#include <QDBusConnectionInterface>
+
+MessageCenterPlugin::MessageCenterPlugin(QWidget* parent, QString ID) : LDPlugin(parent, ID){
+ //Setup the UI
+ QVBoxLayout *vlay = new QVBoxLayout();
+ this->setLayout( new QVBoxLayout() );
+ this->layout()->setContentsMargins(0,0,0,0);
+ vlay->setContentsMargins(3,3,3,3);
+ frame = new QFrame(this);
+ frame->setObjectName("messagecenterbase");
+ this->layout()->addWidget(frame);
+ frame->setLayout(vlay);
+
+
+ //Setup the title bar header buttons
+ QHBoxLayout *hlay = new QHBoxLayout();
+ tool_clearall = new QToolButton(this);
+ tool_clearall->setAutoRaise(true);
+ tool_clearone = new QToolButton(this);
+ tool_clearone->setAutoRaise(true);
+ QWidget *spacer = new QWidget(this);
+ spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ hlay->addWidget(spacer);
+ hlay->addWidget(tool_clearone);
+ hlay->addWidget(tool_clearall);
+ vlay->addLayout(hlay);
+
+ //Setup the main text widget
+ list_messages = new QListWidget(this);
+ list_messages->setSelectionMode(QAbstractItemView::SingleSelection);
+ list_messages->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ vlay->addWidget(list_messages);
+
+ //Now setup the initial values
+ this->setInitialSize(200,300);
+ //Setup the button connections
+ connect(tool_clearall, SIGNAL(clicked()), this, SLOT(clearAllMessages()) );
+ connect(tool_clearone, SIGNAL(clicked()), this, SLOT(clearSelectedMessage()) );
+
+ //Setup the DBUS signals/slots
+ if(QDBusConnection::sessionBus().isConnected()){
+ if( QDBusConnection::sessionBus().registerService("org.freedesktop.Notifications") ){
+ //Was able to register this service, also register everything it can do...
+ //SUPPORTED: "body", "body-hyperlinks", "body-markup", "icon-static"
+
+
+ }
+ QDBusConnection::sessionBus().connect("", "", "org.freedesktop.Notifications", "Notify", this, SLOT(newMessage(QString, uint, QString, QString, QString, QStringList, dict, int)) );
+ QDBusConnection::sessionBus().interface().call("AddMatch", "interface='org.freedesktop.Notifications',member='Notify',type='method_call',eavesdrop='true'");
+ qDebug() << "Available Session DBUS Services:" << QDBusConnection::sessionBus().interface()->registeredServiceNames().value();
+ //connect(QString(), QString(),
+ }
+ if(QDBusConnection::systemBus().isConnected()){
+ qDebug() << "Available System DBUS Services:" << QDBusConnection::systemBus().interface()->registeredServiceNames().value();
+ }
+
+ QTimer::singleShot(0,this, SLOT(loadIcons()) );
+}
+
+MessageCenterPlugin::~MessageCenterPlugin(){
+
+}
+
+void MessageCenterPlugin::newMessage(QString summary, QString body){
+ qDebug() << "New Message:" << summary, body;
+}
+
+void MessageCenterPlugin::clearAllMessages(){
+ list_messages->clear();
+}
+
+void MessageCenterPlugin::clearSelectedMessage(){
+ if( list_messages->currentItem()==0){ return; } //nothing selected
+ list_messages->removeItemWidget( list_messages->currentItem() );
+}
+
+
+void MessageCenterPlugin::loadIcons(){
+ tool_clearall->setIcon( LXDG::findIcon("edit-clear-list","") );
+ tool_clearall->setToolTip( tr("Clear all messages") );
+ tool_clearone->setIcon( LXDG::findIcon("edit-delete","") );
+ tool_clearone->setToolTip( tr("Clear selected message") );
+
+}
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/messagecenter/MessageCenter.h b/src-qt5/core/lumina-desktop/desktop-plugins/messagecenter/MessageCenter.h
new file mode 100644
index 00000000..8491546f
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/messagecenter/MessageCenter.h
@@ -0,0 +1,48 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This plugin is a simple DBUS monitor which display's messages that come in
+//===========================================
+#ifndef _LUMINA_DESKTOP_MESSAGE_CENTER_PLUGIN_H
+#define _LUMINA_DESKTOP_MESSAGE_CENTER_PLUGIN_H
+
+#include <QListWidget>
+#include <QToolButton>
+#include <QFrame>
+
+#include <QTimer>
+#include "../LDPlugin.h"
+
+class MessageCenterPlugin : public LDPlugin{
+ Q_OBJECT
+public:
+ MessageCenterPlugin(QWidget* parent, QString ID);
+ ~MessageCenterPlugin();
+
+private:
+ //QDBusConnection *sess, *sys;
+ QListWidget *list_messages;
+ QFrame *frame;
+ QToolButton *tool_clearall; //clear all messages
+ QToolButton *tool_clearone; //clear selected message
+
+private slots:
+ //void newMessage(QDBusMessage *message);
+ void clearAllMessages();
+ void clearSelectedMessage();
+
+ void loadIcons();
+
+public slots:
+ void LocaleChange(){
+ QTimer::singleShot(0,this, SLOT(loadIcons()));
+ }
+ void ThemeChange(){
+ QTimer::singleShot(0,this, SLOT(loadIcons()));
+ }
+
+};
+#endif
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/notepad/NotepadPlugin.cpp b/src-qt5/core/lumina-desktop/desktop-plugins/notepad/NotepadPlugin.cpp
new file mode 100644
index 00000000..435a57c2
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/notepad/NotepadPlugin.cpp
@@ -0,0 +1,329 @@
+#include "NotepadPlugin.h"
+
+#include <LuminaXDG.h>
+#include "LSession.h"
+#include <LuminaUtils.h>
+#include <QDir>
+#include <QFileDialog>
+#include <QInputDialog>
+#include <QtConcurrent>
+
+NotePadPlugin::NotePadPlugin(QWidget* parent, QString ID) : LDPlugin(parent, ID){
+ //qDebug() << "Creating Notepad Plugin:";
+ QVBoxLayout *vlay = new QVBoxLayout();
+ this->setLayout( new QVBoxLayout() );
+ this->layout()->setContentsMargins(0,0,0,0);
+ vlay->setContentsMargins(3,3,3,3);
+ frame = new QFrame(this);
+ frame->setObjectName("notepadbase");
+ //frame->setStyleSheet("QFrame#notepadbase{border-width: 1px; background: rgba(255,255,255,50); color: black;} QFrame{ border: none; border-radius: 3px; background: rgba(255,255,255,100); color: black;}");
+ this->layout()->addWidget(frame);
+ frame->setLayout(vlay);
+
+ if(!QFile::exists(QDir::homePath()+"/Notes")){
+ //Create the notes directory if non-existant
+ QDir dir;
+ dir.mkpath(QDir::homePath()+"/Notes");
+ }
+ watcher = new QFileSystemWatcher(this);
+ //Always watch the notes directory for new files/changes
+ watcher->addPath(QDir::homePath()+"/Notes");
+
+ typeTimer = new QTimer(this);
+ typeTimer->setInterval(1000); // 1 second before it saves
+ typeTimer->setSingleShot(true); //compress lots of signals into a single save
+
+ updating = false;
+ //Setup the title bar header buttons
+ QHBoxLayout *hlay = new QHBoxLayout();
+ config = new QToolButton(this);
+ config->setAutoRaise(true);
+ config->setMenu(new QMenu(this));
+ config->setPopupMode(QToolButton::InstantPopup);
+ /*open = new QToolButton(this);
+ open->setAutoRaise(true);
+ add = new QToolButton(this);
+ add->setAutoRaise(true);
+ rem = new QToolButton(this);
+ rem->setAutoRaise(true);*/
+ cnote = new QComboBox(this);
+
+ hlay->addWidget(cnote);
+ hlay->addWidget(config);
+ //hlay->addWidget(open);
+ //hlay->addWidget(add);
+ //hlay->addWidget(rem);
+ vlay->addLayout(hlay);
+
+ //Setup the main text widget
+ edit = new QPlainTextEdit(this);
+ edit->setReadOnly(false);
+ edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ vlay->addWidget(edit);
+
+ //Now load the new file-based system for saving notes
+ //qDebug() << "Saving a new setting";
+ this->saveSetting("customFile",""); //always clear this when the plugin is initialized (only maintained per-session)
+ //qDebug() << "Loading Notes Dir";
+ QTimer::singleShot(2000, this, SLOT(notesDirChanged()));
+ //qDebug() << "Set Sizing";
+
+ //qDebug() << "Connect Signals/slots";
+ //Setup the button connections
+ /*connect(open, SIGNAL(clicked()), this, SLOT(openNoteClicked()) );
+ connect(add, SIGNAL(clicked()), this, SLOT(newNoteClicked()) );
+ connect(rem, SIGNAL(clicked()), this, SLOT(remNote()) );*/
+ //connect(config, SIGNAL(clicked()), this, SLOT(openConfigMenu()) );
+ connect(edit, SIGNAL(textChanged()), this, SLOT(newTextAvailable()) );
+ connect(cnote, SIGNAL(currentIndexChanged(QString)), this, SLOT(noteChanged()) );
+ connect(typeTimer, SIGNAL(timeout()), this, SLOT(updateContents()) );
+ connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(notesDirChanged()) ); //re-load the available notes
+ connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(noteChanged()) ); //re-load the current file
+ QTimer::singleShot(0,this, SLOT(loadIcons()) );
+ //qDebug() << " - Done with init";
+}
+
+NotePadPlugin::~NotePadPlugin(){
+
+}
+
+
+void NotePadPlugin::openNote(){
+ //qDebug() << "Open New Note:";
+ //Prompt for a name for the new note
+ QFileDialog dlg(0, Qt::Dialog | Qt::WindowStaysOnTopHint );
+ dlg.setFileMode(QFileDialog::ExistingFile);
+ dlg.setAcceptMode(QFileDialog::AcceptOpen);
+ dlg.setNameFilters( QStringList() << tr("Note Files (*.note)") << tr("Text Files (*)"));
+ dlg.setWindowTitle(tr("Open a note file"));
+ dlg.setWindowIcon( LXDG::findIcon("document-open","") );
+ dlg.setDirectory(QDir::homePath()); //start in the home directory
+ //ensure it is centered on the current screen
+ QPoint center = QApplication::desktop()->screenGeometry(this).center();
+ dlg.move( center.x()-(dlg.width()/2), center.y()-(dlg.height()/2) );
+ dlg.show();
+ while( dlg.isVisible() ){
+ QApplication::processEvents();
+ }
+ QStringList sel = dlg.selectedFiles();
+ if(sel.isEmpty() || dlg.result()!=QDialog::Accepted){ return; } //cancelled
+ QString fullpath = sel.first();
+ QString name = fullpath.section("/",-1);
+ //qDebug() << " - Found Note:" << name << fullpath;
+ int index = cnote->findText(name, Qt::MatchExactly | Qt::MatchCaseSensitive);
+ if(QFile::exists(fullpath) && index <0){
+ //Alternate option of searching for the file in the list
+ index = cnote->findText(fullpath, Qt::MatchExactly | Qt::MatchCaseSensitive);
+ }
+ if(index>=0){
+ //This note already exists: just load it
+ cnote->setCurrentIndex(index);
+ }else{
+ //New note - add it to the end of the list and then load it
+ cnote->addItem(name, fullpath);
+ this->saveSetting("customFile", fullpath); //save this as a custom file
+ cnote->setCurrentIndex( cnote->count()-1 );
+ QTimer::singleShot(1000, this, SLOT(notesDirChanged())); //Make sure to refresh the list (only one custom file at a time)
+ }
+}
+
+QString NotePadPlugin::newNoteName(QString oldname, bool tryagain){
+ //Prompt for a name for the new note
+ //qDebug() << "Create new note";
+ QInputDialog dlg(0, Qt::Dialog | Qt::WindowStaysOnTopHint );
+ dlg.setInputMode(QInputDialog::TextInput);
+ dlg.setLabelText(tr("Name:"));
+ dlg.setTextEchoMode(QLineEdit::Normal);
+ if(tryagain){ dlg.setWindowTitle(tr("Invalid Note Name: Try Again")); }
+ else{ dlg.setWindowTitle(tr("Select a Note Name")); }
+ dlg.setWindowIcon( LXDG::findIcon("document-new","") );
+ dlg.setTextValue(oldname);
+ //ensure it is centered on the current screen
+ QPoint center = QApplication::desktop()->screenGeometry(this).center();
+ dlg.move( center.x()-(dlg.width()/2), center.y()-(dlg.height()/2) );
+ dlg.show();
+ while( dlg.isVisible() ){
+ //this->thread()->usleep(300000); //300 ms between updates
+ QApplication::processEvents();
+ }
+ QString name = dlg.textValue();
+ //make sure to remove any "bad" characters from the name
+ name.remove("\""); name.remove(";"); name.remove("\'"); name.replace("/","_");
+ if(name.isEmpty() || dlg.result()!=QDialog::Accepted){ return ""; } //cancelled
+ //Check validity of the new note filename
+ QString fullpath = QDir::homePath()+"/Notes/"+name;
+ if(!fullpath.endsWith(".note")){ fullpath.append(".note"); }
+ if(QFile::exists(fullpath)){
+ return newNoteName(name, true); //try again
+ }
+ return name; //good name - go ahead and return it
+}
+
+void NotePadPlugin::updateConfigMenu(){
+ //Re-create the menu and open it
+ config->menu()->clear();
+ config->menu()->addAction(LXDG::findIcon("document-open",""), tr("Open Text File"), this, SLOT(openNoteClicked()) );
+ config->menu()->addAction(LXDG::findIcon("document-new",""), tr("Create a Note"), this, SLOT(newNoteClicked()) );
+ if(cnote->currentIndex()>=0){
+ config->menu()->addSeparator();
+ config->menu()->addAction(LXDG::findIcon("document-edit",""), tr("Rename Note"), this, SLOT(renameNote()) );
+ config->menu()->addAction(LXDG::findIcon("document-close",""), tr("Delete Note"), this, SLOT(remNote()) );
+ }
+}
+
+void NotePadPlugin::openNoteClicked(){
+ openNote();
+}
+
+void NotePadPlugin::newNoteClicked(){
+ //QtConcurrent::run(this, &NotePadPlugin::newNote);
+ QString name = newNoteName();
+ if(name.isEmpty()){ return; }
+ QString fullpath = QDir::homePath()+"/Notes/"+name;
+ if(!fullpath.endsWith(".note")){ fullpath.append(".note"); }
+ //qDebug() << " - New Note:" << name << fullpath;
+ int index = cnote->findText(name, Qt::MatchExactly | Qt::MatchCaseSensitive);
+ if(QFile::exists(fullpath) && index <0){
+ //Alternate option of searching for the file in the list
+ index = cnote->findText(fullpath, Qt::MatchExactly | Qt::MatchCaseSensitive);
+ }
+ if(index>=0){
+ //This note already exists: just load it
+ cnote->setCurrentIndex(index);
+ }else{
+ //New note - add it to the end of the list and then load it
+ cnote->addItem(name, fullpath);
+ cnote->setCurrentIndex( cnote->count()-1 );
+ }
+}
+
+void NotePadPlugin::remNote(){
+ QString note = cnote->currentData().toString();
+ if(note.isEmpty()){ return; }
+ watcher->removePath(note); //remove this file from the watcher
+ this->saveSetting("currentFile",""); //reset the internal value
+ QFile::remove(note); //remove the file
+ //if(!note.startsWith(QDir::homePath()+"/Notes/") ){
+ //If the file was not in the notes directory, need to manually prompt for a re-load
+ // otherwise, the directory watcher will catch it and trigger a re-load (no need to double-load)
+ notesDirChanged();
+ //}
+}
+
+void NotePadPlugin::renameNote(){
+ int item = cnote->currentIndex();
+ if(item<0){ return; } //nothing selected
+ QString oldpath = cnote->currentData().toString();
+ if(oldpath.isEmpty() || !oldpath.endsWith(".note")){ return; }
+ QString name = newNoteName(cnote->currentText());
+ if(name.isEmpty()){ return; }
+ QString fullpath = QDir::homePath()+"/Notes/"+name;
+ if(!fullpath.endsWith(".note")){ fullpath.append(".note"); }
+ //qDebug() << " - New Note:" << name << fullpath;
+ //Update the current item data to point to this file
+ cnote->setItemText(item, name);
+ cnote->setItemData(item, fullpath);
+ //Now move the file over
+ QFile::rename(oldpath, fullpath);
+ noteChanged();
+}
+
+void NotePadPlugin::newTextAvailable(){
+ if(updating){ return; } //programmatic change of the widget
+ if(typeTimer->isActive()){ typeTimer->stop(); }
+ typeTimer->start();
+}
+
+void NotePadPlugin::updateContents(){
+ if(updating){ return; } //this was a programmatic change to the widget
+ //The text was changed in the plugin - save it in the file
+ QString note = cnote->currentData().toString();
+ updating = true;
+ LUtils::writeFile(note, edit->toPlainText().split("\n"), true);
+ QApplication::processEvents(); //make sure to process/discard the file changed signal before disabling the flag
+ updating = false;
+}
+
+void NotePadPlugin::notesDirChanged(){
+ if(updating){ return; }
+ QString cfile = this->readSetting("currentFile","").toString();
+ QStringList notes;
+ QDir dir(QDir::homePath()+"/Notes");
+ QStringList files = dir.entryList(QStringList() << "*.note", QDir::Files | QDir::NoDotAndDotDot, QDir::Name);
+ for(int i=0; i<files.length(); i++){
+ notes << dir.absoluteFilePath(files[i]);
+ }
+ QString custom = this->readSetting("customFile","").toString();
+ if(!custom.isEmpty() && QFile::exists(custom) ){ notes << custom; }
+ //qDebug() << "Available Notes:" << notes << cfile;
+ //Now update the UI list
+ updating = true; //don't refresh the UI until done changing lists
+ cnote->clear();
+ bool found = false;
+ for(int i=0; i<notes.length(); i++){
+ QString name = notes[i].section("/",-1);
+ if(name.endsWith(".note")){ name.chop(5); }
+ cnote->addItem(name, notes[i]);
+ if(notes[i]==cfile){ cnote->setCurrentIndex(i); found = true;}
+ }
+ if(!found && !cfile.isEmpty() && QFile::exists(cfile)){
+ //Current note is a manually-loaded text file
+ cnote->addItem(cfile.section("/",-1), cfile);
+ cnote->setCurrentIndex( cnote->count()-1 ); //last item
+ found = true;
+ }
+ if(!found && cnote->count()>0){ cnote->setCurrentIndex(0); }
+ updating =false;
+ noteChanged();
+}
+
+void NotePadPlugin::noteChanged(){
+ if(updating){ return; }
+ updating =true;
+ QString note;
+ if(cnote->currentIndex()>=0){
+ note = cnote->currentData().toString();
+ }
+ QTimer::singleShot(0, this, SLOT(updateConfigMenu()) );
+ if(note.isEmpty() && cnote->count()>0){
+ updating=false;
+ cnote->setCurrentIndex(0);
+ return;
+ }
+ QString oldnote = this->readSetting("currentFile","").toString();
+ //qDebug() << "Note Changed:" << note << oldnote;
+ if( oldnote!=note ){
+ //Clear the old note file/setting
+ if(!oldnote.isEmpty()){
+ watcher->removePath(oldnote);
+ this->saveSetting("currentFile","");
+ }
+ if(!note.isEmpty()){
+ this->saveSetting("currentFile",note);
+ watcher->addPath(note);
+ }
+ }
+
+ if(!note.isEmpty()){
+ QString text = LUtils::readFile(note).join("\n");
+ if(text!=edit->toPlainText()){
+ edit->setPlainText( text );
+ }
+ }else{
+ edit->clear();
+ }
+ //If no notes available - disable the editor until a new one is created
+ edit->setEnabled(!note.isEmpty());
+ //rem->setEnabled(!note.isEmpty());
+ cnote->setEnabled(!note.isEmpty());
+ //leave the new/open buttons enabled all the time
+ updating = false;
+}
+
+
+void NotePadPlugin::loadIcons(){
+ /*open->setIcon( LXDG::findIcon("document-open","") );
+ add->setIcon( LXDG::findIcon("document-new","") );
+ rem->setIcon( LXDG::findIcon("document-close","") );*/
+ config->setIcon( LXDG::findIcon("configure","") );
+}
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/notepad/NotepadPlugin.h b/src-qt5/core/lumina-desktop/desktop-plugins/notepad/NotepadPlugin.h
new file mode 100644
index 00000000..5084dadf
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/notepad/NotepadPlugin.h
@@ -0,0 +1,66 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This plugin is a simple text editor for notes on the desktop
+//===========================================
+#ifndef _LUMINA_DESKTOP_NOTEPAD_PLUGIN_H
+#define _LUMINA_DESKTOP_NOTEPAD_PLUGIN_H
+
+#include <QPlainTextEdit>
+#include <QToolButton>
+#include <QComboBox>
+#include <QVBoxLayout>
+#include <QTimer>
+#include <QFileSystemWatcher>
+#include "../LDPlugin.h"
+
+class NotePadPlugin : public LDPlugin{
+ Q_OBJECT
+public:
+ NotePadPlugin(QWidget* parent, QString ID);
+ ~NotePadPlugin();
+
+ virtual QSize defaultPluginSize(){
+ // The returned QSize is in grid points (typically 100 or 200 pixels square)
+ return QSize(3,3);
+ }
+private:
+ QPlainTextEdit *edit;
+ QToolButton *config; //*open, *add, *rem;
+ QComboBox *cnote;
+ QFrame *frame;
+ QFileSystemWatcher *watcher;
+ bool updating;
+ QTimer *typeTimer;
+
+ void openNote();
+ QString newNoteName(QString oldname = "", bool tryagain = false);
+
+private slots:
+ void updateConfigMenu();
+
+ void openNoteClicked();
+ void newNoteClicked();
+ void remNote();
+ void renameNote();
+ void newTextAvailable();
+ void updateContents();
+
+ void notesDirChanged();
+ void noteChanged();
+
+ void loadIcons();
+
+public slots:
+ void LocaleChange(){
+ QTimer::singleShot(0,this, SLOT(noteChanged()));
+ }
+ void ThemeChange(){
+ QTimer::singleShot(0,this, SLOT(loadIcons()));
+ }
+
+};
+#endif
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/quickcontainer/QuickDPlugin.h b/src-qt5/core/lumina-desktop/desktop-plugins/quickcontainer/QuickDPlugin.h
new file mode 100644
index 00000000..4ba74133
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/quickcontainer/QuickDPlugin.h
@@ -0,0 +1,51 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This class is a simple container for a QtQuick plugin
+//===========================================
+#ifndef _LUMINA_DESKTOP_DESKTOP_PLUGIN_QUICK_H
+#define _LUMINA_DESKTOP_DESKTOP_PLUGIN_QUICK_H
+
+#include <QQuickWidget>
+#include <QVBoxLayout>
+#include "../LDPlugin.h"
+
+#include <LuminaUtils.h>
+
+class QuickDPlugin : public LDPlugin{
+ Q_OBJECT
+public:
+ QuickDPlugin(QWidget* parent, QString ID) : LDPlugin(parent, ID){
+ this->setLayout( new QVBoxLayout());
+ this->layout()->setContentsMargins(0,0,0,0);
+ container = new QQuickWidget(this);
+ container->setResizeMode(QQuickWidget::SizeRootObjectToView);
+ connect(container, SIGNAL(statusChanged(QQuickWidget::Status)), this, SLOT(statusChange(QQuickWidget::Status)) );
+ this->layout()->addWidget(container);
+ container->setSource(QUrl::fromLocalFile( LUtils::findQuickPluginFile(ID.section("---",0,0)) ));
+ QApplication::processEvents(); //to check for errors right away
+ //this->setInitialSize(container->initialSize().width(), container->initialSize().height());
+ }
+
+ ~QuickDPlugin(){}
+
+ virtual QSize defaultPluginSize(){
+ // The returned QSize is in grid points (typically 100 or 200 pixels square)
+ return QSize(2,2);
+ }
+private:
+ QQuickWidget *container;
+
+private slots:
+ void statusChange(QQuickWidget::Status status){
+ if(status == QQuickWidget::Error){
+ qDebug() << "Quick Widget Error:" << this->ID();
+ container->setSource(QUrl()); //clear out the script - experienced an error
+ }
+ }
+
+};
+#endif
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/systemmonitor/MonitorWidget.cpp b/src-qt5/core/lumina-desktop/desktop-plugins/systemmonitor/MonitorWidget.cpp
new file mode 100644
index 00000000..951bcc98
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/systemmonitor/MonitorWidget.cpp
@@ -0,0 +1,63 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "MonitorWidget.h"
+#include "ui_MonitorWidget.h"
+
+
+#include <LuminaXDG.h>
+#include <LuminaOS.h>
+
+MonitorWidget::MonitorWidget(QWidget *parent) : QWidget(parent), ui(new Ui::MonitorWidget()){
+ ui->setupUi(this); //load the designer form
+ upTimer = new QTimer(this);
+ upTimer->setInterval(2000); //update every 2 seconds
+ connect(upTimer, SIGNAL(timeout()), this, SLOT(UpdateStats()) );
+ LoadIcons();
+ upTimer->start();
+}
+
+MonitorWidget::~MonitorWidget(){
+ //qDebug() << "Removing MonitorWidget";
+}
+
+void MonitorWidget::LoadIcons(){
+ ui->tabWidget->setTabIcon(0,LXDG::findIcon("appointment-recurring","") ); //Summary
+ ui->tabWidget->setTabIcon(1,LXDG::findIcon("drive-harddisk","") ); //Disk Usage
+ //ui->tabWidget->setTabIcon(1,LXDG::findIcon("cpu","") ); //CPU Log
+ //ui->tabWidget->setTabIcon(2,LXDG::findIcon("media-flash-memory-stick","") ); //Mem Log
+}
+
+void MonitorWidget::UpdateStats(){
+ //qDebug() << "Updating System statistics...";
+ ui->label_temps->setText( LOS::CPUTemperatures().join(", ") );
+ if(ui->progress_cpu->isEnabled()){
+ int perc = LOS::CPUUsagePercent();
+ ui->progress_cpu->setValue(perc);
+ if(perc<0){ ui->progress_cpu->setEnabled(false); } //disable this for future checks
+ }
+ if(ui->progress_mem->isEnabled()){
+ int perc = LOS::MemoryUsagePercent();
+ ui->progress_mem->setValue(perc);
+ if(perc<0){ ui->progress_mem->setEnabled(false); } //disable this for future checks
+ }
+ ui->label_diskinfo->setText( LOS::DiskUsage().join("\n") );
+ //Also perform/update the logs as necessary
+ // -- TO DO --
+}
+
+SysMonitorPlugin::SysMonitorPlugin(QWidget *parent, QString ID) : LDPlugin(parent, ID){
+ monitor = new MonitorWidget(this);
+ this->setLayout( new QVBoxLayout() );
+ this->layout()->setContentsMargins(0,0,0,0);
+ this->layout()->addWidget(monitor);
+
+ //this->setInitialSize(monitor->sizeHint().width(),monitor->sizeHint().height());
+}
+
+SysMonitorPlugin::~SysMonitorPlugin(){
+ //qDebug() << "Remove SysMonitorPlugin";
+} \ No newline at end of file
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/systemmonitor/MonitorWidget.h b/src-qt5/core/lumina-desktop/desktop-plugins/systemmonitor/MonitorWidget.h
new file mode 100644
index 00000000..618ac8f4
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/systemmonitor/MonitorWidget.h
@@ -0,0 +1,62 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This plugin is a simple hardware status monitor on the desktop
+//===========================================
+#ifndef _LUMINA_DESKTOP_PLUGIN_HW_MONITOR_WIDGET_H
+#define _LUMINA_DESKTOP_PLUGIN_HW_MONITOR_WIDGET_H
+
+#include <QTimer>
+#include <QWidget>
+
+#include "../LDPlugin.h"
+
+namespace Ui{
+ class MonitorWidget;
+};
+
+class MonitorWidget : public QWidget{
+ Q_OBJECT
+public:
+ MonitorWidget(QWidget *parent = 0);
+ ~MonitorWidget();
+
+public slots:
+ void LoadIcons();
+
+private:
+ Ui::MonitorWidget *ui;
+ QTimer *upTimer;
+
+private slots:
+ void UpdateStats();
+};
+
+// Wrapper class to put this into a desktop plugin container
+class SysMonitorPlugin : public LDPlugin{
+ Q_OBJECT
+public:
+ SysMonitorPlugin(QWidget* parent, QString ID);
+ ~SysMonitorPlugin();
+
+ virtual QSize defaultPluginSize(){
+ // The returned QSize is in grid points (typically 100 or 200 pixels square)
+ return QSize(3,2);
+ }
+
+private:
+ MonitorWidget *monitor;
+
+public slots:
+ void LocaleChange(){
+ QTimer::singleShot(0,monitor, SLOT(LoadIcons()));
+ }
+ void ThemeChange(){
+ QTimer::singleShot(0,monitor, SLOT(LoadIcons()));
+ }
+};
+
+#endif
diff --git a/src-qt5/core/lumina-desktop/desktop-plugins/systemmonitor/MonitorWidget.ui b/src-qt5/core/lumina-desktop/desktop-plugins/systemmonitor/MonitorWidget.ui
new file mode 100644
index 00000000..8798bc25
--- /dev/null
+++ b/src-qt5/core/lumina-desktop/desktop-plugins/systemmonitor/MonitorWidget.ui
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MonitorWidget</class>
+ <widget class="QWidget" name="MonitorWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>300</width>
+ <height>122</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <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="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab_summary">
+ <attribute name="title">
+ <string>Summary</string>
+ </attribute>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>CPU Temp:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="label_temps">
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>CPU Usage:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QProgressBar" name="progress_cpu">
+ <property name="value">
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Mem Usage:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QProgressBar" name="progress_mem">
+ <property name="value">
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_disks">
+ <attribute name="title">
+ <string>Disk I/O</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <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="QScrollArea" name="scrollArea">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>292</width>
+ <height>89</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="label_diskinfo">
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
bgstack15