diff options
Diffstat (limited to 'src-qt5/core/lumina-desktop/desktop-plugins')
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> |