commit
097e16cee7
42 changed files with 3571 additions and 432 deletions
@ -1,355 +0,0 @@ |
||||
/*
|
||||
* Copyright 2008 Aaron Seigo <aseigo@kde.org> |
||||
* Copyright 2013 Sebastian Kügler <sebas@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU Library General Public License as |
||||
* published by the Free Software Foundation; either version 2, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details |
||||
* |
||||
* You should have received a copy of the GNU Library General Public |
||||
* License along with this program; if not, write to the |
||||
* Free Software Foundation, Inc., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
*/ |
||||
|
||||
#include "desktopcorona.h" |
||||
|
||||
#include <QApplication> |
||||
#include <QDebug> |
||||
#include <QDesktopWidget> |
||||
#include <QQmlContext> |
||||
#include <QTimer> |
||||
|
||||
#include <KLocalizedString> |
||||
#include <Plasma/Package> |
||||
|
||||
#include "containmentconfigview.h" |
||||
#include "panelview.h" |
||||
#include "view.h" |
||||
#include "scripting/desktopscriptengine.h" |
||||
#include "widgetexplorer/widgetexplorerview.h" |
||||
|
||||
|
||||
static const QString s_panelTemplatesPath("plasma-layout-templates/panels/*"); |
||||
|
||||
DesktopCorona::DesktopCorona(QObject *parent) |
||||
: Plasma::Corona(parent), |
||||
m_desktopWidget(QApplication::desktop()), |
||||
m_widgetExplorerView(0) |
||||
{ |
||||
m_desktopDefaultsConfig = KConfigGroup(KSharedConfig::openConfig(package().filePath("defaults")), "Desktop"); |
||||
|
||||
m_appConfigSyncTimer = new QTimer(this); |
||||
m_appConfigSyncTimer->setSingleShot(true); |
||||
connect(m_appConfigSyncTimer, &QTimer::timeout, |
||||
this, &DesktopCorona::syncAppConfig); |
||||
|
||||
connect(m_desktopWidget, SIGNAL(resized(int)), |
||||
this, SLOT(screenResized(int))); |
||||
connect(m_desktopWidget, SIGNAL(screenCountChanged(int)), |
||||
this, SLOT(screenCountChanged(int))); |
||||
connect(m_desktopWidget, SIGNAL(workAreaResized(int)), |
||||
this, SLOT(workAreaResized(int))); |
||||
connect(this, &DesktopCorona::containmentAdded, this, &DesktopCorona::handleContainmentAdded); |
||||
|
||||
connect(this, SIGNAL(screenOwnerChanged(int, int, Plasma::Containment *)), |
||||
this, SLOT(updateScreenOwner(int, int, Plasma::Containment *))); |
||||
checkViews(); |
||||
|
||||
//QTimer::singleShot(600, this, SLOT(showWidgetExplorer())); // just for easier debugging
|
||||
} |
||||
|
||||
DesktopCorona::~DesktopCorona() |
||||
{ |
||||
} |
||||
|
||||
KSharedConfig::Ptr DesktopCorona::applicationConfig() |
||||
{ |
||||
return KSharedConfig::openConfig(); |
||||
} |
||||
|
||||
void DesktopCorona::requestApplicationConfigSync() |
||||
{ |
||||
// constant controlling how long between requesting a configuration sync
|
||||
// and one happening should occur. currently 10 seconds
|
||||
static const int CONFIG_SYNC_TIMEOUT = 10000; |
||||
|
||||
m_appConfigSyncTimer->start(CONFIG_SYNC_TIMEOUT); |
||||
} |
||||
|
||||
void DesktopCorona::loadDefaultLayout() |
||||
{ |
||||
WorkspaceScripting::DesktopScriptEngine scriptEngine(this, true); |
||||
connect(&scriptEngine, &WorkspaceScripting::ScriptEngine::printError, |
||||
this, &DesktopCorona::printScriptError); |
||||
connect(&scriptEngine, &WorkspaceScripting::ScriptEngine::print, |
||||
this, &DesktopCorona::printScriptMessage); |
||||
|
||||
QString script = package().filePath("defaultlayout"); |
||||
|
||||
QFile file(script); |
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text) ) { |
||||
QString code = file.readAll(); |
||||
qDebug() << "evaluating startup script:" << script; |
||||
scriptEngine.evaluateScript(code); |
||||
} |
||||
} |
||||
|
||||
void DesktopCorona::processUpdateScripts() |
||||
{ |
||||
foreach (const QString &script, WorkspaceScripting::ScriptEngine::pendingUpdateScripts(this)) { |
||||
WorkspaceScripting::DesktopScriptEngine scriptEngine(this, false); |
||||
scriptEngine.evaluateScript(script); |
||||
} |
||||
} |
||||
|
||||
void DesktopCorona::checkScreens(bool signalWhenExists) |
||||
{ |
||||
// quick sanity check to ensure we have containments for each screen
|
||||
int num = numScreens(); |
||||
for (int i = 0; i < num; ++i) { |
||||
checkScreen(i, signalWhenExists); |
||||
} |
||||
} |
||||
|
||||
void DesktopCorona::checkScreen(int screen, bool signalWhenExists) |
||||
{ |
||||
// signalWhenExists is there to allow PlasmaApp to know when to create views
|
||||
// it does this only on containment addition, but in the case of a screen being
|
||||
// added and the containment already existing for that screen, no signal is emitted
|
||||
// and so PlasmaApp does not know that it needs to create a view for it. to avoid
|
||||
// taking care of that case in PlasmaApp (which would duplicate some of the code below,
|
||||
// DesktopCorona will, when signalWhenExists is true, emit a containmentAdded signal
|
||||
// even if the containment actually existed prior to this method being called.
|
||||
//
|
||||
//note: hte signal actually triggers view creation only for panels, atm.
|
||||
//desktop views are created in response to containment's screenChanged signal instead, which is
|
||||
//buggy (sometimes the containment thinks it's already on the screen, so no view is created)
|
||||
|
||||
//TODO: restore activities
|
||||
//Activity *currentActivity = activity(m_activityController->currentActivity());
|
||||
//ensure the desktop(s) have a containment and view
|
||||
checkDesktop(/*currentActivity,*/ signalWhenExists, screen); |
||||
|
||||
|
||||
//ensure the panels get views too
|
||||
if (signalWhenExists) { |
||||
foreach (Plasma::Containment * c, containments()) { |
||||
if (c->screen() != screen) { |
||||
continue; |
||||
} |
||||
|
||||
Plasma::Types::ContainmentType t = c->containmentType(); |
||||
if (t == Plasma::Types::PanelContainment || |
||||
t == Plasma::Types::CustomPanelContainment) { |
||||
emit containmentAdded(c); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
void DesktopCorona::checkDesktop(/*Activity *activity,*/ bool signalWhenExists, int screen) |
||||
{ |
||||
Plasma::Containment *c = /*activity->*/containmentForScreen(screen); |
||||
|
||||
//TODO: remove following when activities are restored
|
||||
if (!c) { |
||||
c = createContainment(m_desktopDefaultsConfig.readEntry("Containment", "org.kde.desktopcontainment")); |
||||
} |
||||
|
||||
if (!c) { |
||||
return; |
||||
} |
||||
|
||||
c->setScreen(screen); |
||||
if (screen >= 0 || m_views.count() >= screen + 1) { |
||||
m_views[screen]->setContainment(c); |
||||
} else { |
||||
qWarning() << "Invalid screen"; |
||||
} |
||||
c->flushPendingConstraintsEvents(); |
||||
requestApplicationConfigSync(); |
||||
|
||||
if (signalWhenExists) { |
||||
emit containmentAdded(c); |
||||
} |
||||
} |
||||
|
||||
int DesktopCorona::numScreens() const |
||||
{ |
||||
return m_desktopWidget->screenCount(); |
||||
} |
||||
|
||||
QRect DesktopCorona::screenGeometry(int id) const |
||||
{ |
||||
return m_desktopWidget->screenGeometry(id); |
||||
} |
||||
|
||||
QRegion DesktopCorona::availableScreenRegion(int id) const |
||||
{ |
||||
return m_desktopWidget->availableGeometry(id); |
||||
} |
||||
|
||||
QRect DesktopCorona::availableScreenRect(int id) const |
||||
{ |
||||
return m_desktopWidget->availableGeometry(id); |
||||
} |
||||
|
||||
PanelView *DesktopCorona::panelView(Plasma::Containment *containment) const |
||||
{ |
||||
return m_panelViews.value(containment); |
||||
} |
||||
|
||||
|
||||
///// SLOTS
|
||||
|
||||
void DesktopCorona::screenCountChanged(int newCount) |
||||
{ |
||||
qDebug() << "New screen count" << newCount; |
||||
checkViews(); |
||||
} |
||||
|
||||
void DesktopCorona::screenResized(int screen) |
||||
{ |
||||
qDebug() << "Screen resized" << screen; |
||||
} |
||||
|
||||
void DesktopCorona::workAreaResized(int screen) |
||||
{ |
||||
qDebug() << "Work area resized" << screen; |
||||
} |
||||
|
||||
void DesktopCorona::checkViews() |
||||
{ |
||||
if (m_views.count() == m_desktopWidget->screenCount()) { |
||||
return; |
||||
} else if (m_views.count() < m_desktopWidget->screenCount()) { |
||||
for (int i = m_views.count(); i < m_desktopWidget->screenCount(); ++i) { |
||||
View *view = new View(this); |
||||
QSurfaceFormat format; |
||||
view->show(); |
||||
|
||||
m_views << view; |
||||
} |
||||
} else { |
||||
for (int i = m_desktopWidget->screenCount(); i < m_views.count(); ++i) { |
||||
View *view = m_views.last(); |
||||
view->deleteLater(); |
||||
m_views.pop_back(); |
||||
} |
||||
} |
||||
|
||||
//check every containment is in proper view
|
||||
for (int i = 0; i < m_desktopWidget->screenCount(); ++i) { |
||||
qDebug() << "TODO: Implement loading containments into the views"; |
||||
} |
||||
} |
||||
|
||||
|
||||
void DesktopCorona::checkLoadingDesktopsComplete() |
||||
{ |
||||
Plasma::Containment *c = qobject_cast<Plasma::Containment *>(sender()); |
||||
if (c) { |
||||
disconnect(c, &Plasma::Containment::uiReadyChanged, |
||||
this, &DesktopCorona::checkLoadingDesktopsComplete); |
||||
m_loadingDesktops.remove(c); |
||||
} |
||||
|
||||
if (m_loadingDesktops.isEmpty()) { |
||||
foreach (Plasma::Containment *cont, m_waitingPanels) { |
||||
m_panelViews[cont] = new PanelView(this); |
||||
m_panelViews[cont]->setContainment(cont); |
||||
} |
||||
m_waitingPanels.clear(); |
||||
} |
||||
} |
||||
|
||||
void DesktopCorona::updateScreenOwner(int wasScreen, int isScreen, Plasma::Containment *containment) |
||||
{ |
||||
qDebug() << "Was screen" << wasScreen << "Is screen" << isScreen <<"Containment" << containment << containment->title(); |
||||
|
||||
if (containment->formFactor() == Plasma::Types::Horizontal || |
||||
containment->formFactor() == Plasma::Types::Vertical) { |
||||
|
||||
if (isScreen >= 0) { |
||||
m_waitingPanels << containment; |
||||
} else { |
||||
if (m_panelViews.contains(containment)) { |
||||
m_panelViews[containment]->setContainment(0); |
||||
m_panelViews[containment]->deleteLater(); |
||||
m_panelViews.remove(containment); |
||||
} |
||||
} |
||||
checkLoadingDesktopsComplete(); |
||||
|
||||
//Desktop view
|
||||
} else { |
||||
|
||||
if (containment->isUiReady()) { |
||||
checkLoadingDesktopsComplete(); |
||||
} else { |
||||
m_loadingDesktops.insert(containment); |
||||
connect(containment, &Plasma::Containment::uiReadyChanged, |
||||
this, &DesktopCorona::checkLoadingDesktopsComplete); |
||||
} |
||||
|
||||
if (isScreen < 0 || m_views.count() < isScreen + 1) { |
||||
qWarning() << "Invalid screen"; |
||||
return; |
||||
} |
||||
|
||||
m_views[isScreen]->setContainment(containment); |
||||
} |
||||
} |
||||
|
||||
void DesktopCorona::handleContainmentAdded(Plasma::Containment* c) |
||||
{ |
||||
connect(c, &Plasma::Containment::showAddWidgetsInterface, |
||||
this, &DesktopCorona::showWidgetExplorer); |
||||
} |
||||
|
||||
void DesktopCorona::showWidgetExplorer() |
||||
{ |
||||
if (!m_widgetExplorerView) { |
||||
|
||||
QString expqml = package().filePath("widgetexplorer"); |
||||
qDebug() << "Script to load for WidgetExplorer: " << expqml; |
||||
m_widgetExplorerView = new WidgetExplorerView(expqml); |
||||
m_widgetExplorerView->init(); |
||||
} |
||||
Plasma::Containment *c = 0; |
||||
c = dynamic_cast<Plasma::Containment*>(sender()); |
||||
if (c) { |
||||
qDebug() << "Found containment."; |
||||
m_widgetExplorerView->setContainment(c); |
||||
} else { |
||||
// FIXME: try harder to find a suitable containment?
|
||||
qWarning() << "containment not set, don't know where to add the applet."; |
||||
} |
||||
m_widgetExplorerView->show(); |
||||
} |
||||
|
||||
void DesktopCorona::syncAppConfig() |
||||
{ |
||||
qDebug() << "Syncing plasma-shellrc config"; |
||||
applicationConfig()->sync(); |
||||
} |
||||
|
||||
void DesktopCorona::printScriptError(const QString &error) |
||||
{ |
||||
qWarning() << error; |
||||
} |
||||
|
||||
void DesktopCorona::printScriptMessage(const QString &message) |
||||
{ |
||||
qDebug() << message; |
||||
} |
||||
|
||||
#include "moc_desktopcorona.cpp" |
||||
|
||||
@ -1,5 +1,6 @@ |
||||
|
||||
plasma_install_package(desktop org.kde.desktop plasma/shells shell) |
||||
plasma_install_package(blank org.kde.blank plasma/shells shell) |
||||
plasma_install_package(lookandfeel org.kde.lookandfeel plasma/look-and-feel lookandfeel) |
||||
|
||||
add_subdirectory(wallpapers) |
||||
|
||||
@ -0,0 +1,3 @@ |
||||
#! /usr/bin/env bash |
||||
$XGETTEXT `find . -name \*.qml` -L Java -o $podir/plasma_shell_org.kde.desktop.pot |
||||
rm -f rc.cpp |
||||
@ -0,0 +1,45 @@ |
||||
/* |
||||
* Copyright 2013 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore |
||||
import org.kde.plasma.components 2.0 as PlasmaComponents |
||||
|
||||
Row { |
||||
id: root |
||||
|
||||
property alias reason: messageText.text |
||||
|
||||
clip: true |
||||
|
||||
PlasmaCore.IconItem { |
||||
id: icon |
||||
anchors.verticalCenter: parent |
||||
width: theme.hugeIconSize |
||||
height: width |
||||
source: "dialog-error" |
||||
} |
||||
|
||||
PlasmaComponents.Label { |
||||
id: messageText |
||||
anchors.verticalCenter: parent |
||||
width: parent.width - icon.width |
||||
wrapMode: Text.Wrap |
||||
} |
||||
} |
||||
@ -0,0 +1,68 @@ |
||||
/* |
||||
* Copyright 2013 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
import QtQuick.Window 2.0 |
||||
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore |
||||
import org.kde.plasma.components 2.0 as PlasmaComponents |
||||
|
||||
Item { |
||||
id: root |
||||
|
||||
property Item applet |
||||
property Item compactRepresentation |
||||
|
||||
|
||||
onAppletChanged: { |
||||
applet.parent = appletParent |
||||
applet.anchors.fill = applet.parent |
||||
} |
||||
onCompactRepresentationChanged: { |
||||
compactRepresentation.parent = root |
||||
compactRepresentation.anchors.fill = root |
||||
} |
||||
|
||||
|
||||
PlasmaCore.Dialog { |
||||
id: popupWindow |
||||
//windowFlags: Qt.Popup |
||||
color: Qt.rgba(0,0,0,0) |
||||
visible: plasmoid.expanded |
||||
visualParent: root |
||||
mainItem: Item { |
||||
id: appletParent |
||||
|
||||
width: applet && applet.implicitWidth > 0 ? applet.implicitWidth : theme.mSize(theme.defaultFont).width * 35 |
||||
height: applet && applet.implicitHeight > 0 ? applet.implicitHeight : theme.mSize(theme.defaultFont).height * 25 |
||||
onWidthChanged: applet.width = width |
||||
onHeightChanged: applet.height = height |
||||
} |
||||
|
||||
onActiveWindowChanged: { |
||||
if (!activeWindow) { |
||||
// plasmoid.expanded = false |
||||
} |
||||
} |
||||
onVisibleChanged: { |
||||
if (!visible) { |
||||
plasmoid.expanded = false |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,36 @@ |
||||
/* |
||||
* Copyright 2013 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore |
||||
|
||||
PlasmaCore.IconItem { |
||||
id: icon |
||||
|
||||
source: plasmoid.icon ? plasmoid.icon : "plasma" |
||||
active: mouseArea.containsMouse |
||||
|
||||
MouseArea { |
||||
id: mouseArea |
||||
|
||||
anchors.fill: parent |
||||
hoverEnabled: true |
||||
onClicked: plasmoid.expanded = !plasmoid.expanded |
||||
} |
||||
} |
||||
@ -0,0 +1,237 @@ |
||||
/* |
||||
* Copyright 2013 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
import QtQuick.Controls 1.0 as QtControls |
||||
import QtQuick.Layouts 1.0 |
||||
import org.kde.plasma.configuration 2.0 |
||||
|
||||
|
||||
//TODO: all of this will be done with desktop components |
||||
Rectangle { |
||||
id: root |
||||
|
||||
property int _m: theme.defaultFont.pointSize |
||||
|
||||
//BEGIN properties |
||||
color: syspal.window |
||||
width: 640 |
||||
height: 480 |
||||
//END properties |
||||
|
||||
//BEGIN model |
||||
property ConfigModel globalConfigModel: globalAppletConfigModel |
||||
|
||||
ConfigModel { |
||||
id: globalAppletConfigModel |
||||
ConfigCategory { |
||||
name: "Keyboard shortcuts" |
||||
icon: "preferences-desktop-keyboard" |
||||
source: "ConfigurationShortcuts.qml" |
||||
} |
||||
} |
||||
//END model |
||||
|
||||
//BEGIN functions |
||||
function saveConfig() { |
||||
for (var key in plasmoid.configuration) { |
||||
if (main.currentPage["cfg_"+key] !== undefined) { |
||||
plasmoid.configuration[key] = main.currentPage["cfg_"+key] |
||||
} |
||||
} |
||||
} |
||||
|
||||
function restoreConfig() { |
||||
for (var key in plasmoid.configuration) { |
||||
if (main.currentPage["cfg_"+key] !== undefined) { |
||||
main.currentPage["cfg_"+key] = plasmoid.configuration[key] |
||||
} |
||||
} |
||||
} |
||||
//END functions |
||||
|
||||
|
||||
//BEGIN connections |
||||
Component.onCompleted: { |
||||
if (configDialog.configModel && configDialog.configModel.count > 0) { |
||||
main.sourceFile = configDialog.configModel.get(0).source |
||||
} else { |
||||
main.sourceFile = globalConfigModel.get(0).source |
||||
} |
||||
root.restoreConfig() |
||||
// root.width = mainColumn.implicitWidth |
||||
// root.height = mainColumn.implicitHeight |
||||
} |
||||
//END connections |
||||
|
||||
//BEGIN UI components |
||||
SystemPalette {id: syspal} |
||||
|
||||
ColumnLayout { |
||||
id: mainColumn |
||||
anchors.fill: parent |
||||
property int implicitWidth: Math.max(contentRow.implicitWidth, buttonsRow.implicitWidth) + 8 |
||||
property int implicitHeight: contentRow.implicitHeight + buttonsRow.implicitHeight + 8 |
||||
|
||||
RowLayout { |
||||
id: contentRow |
||||
anchors { |
||||
left: parent.left |
||||
right: parent.right |
||||
} |
||||
Layout.fillHeight: true |
||||
Layout.preferredHeight: parent.height - buttonsRow.height |
||||
|
||||
QtControls.ScrollView{ |
||||
id: categoriesScroll |
||||
frameVisible: true |
||||
anchors { |
||||
top: parent.top |
||||
bottom: parent.bottom |
||||
} |
||||
visible: (configDialog.configModel ? configDialog.configModel.count : 0) + globalConfigModel.count > 1 |
||||
width: visible ? 100 : 0 |
||||
implicitWidth: width |
||||
Flickable { |
||||
id: categoriesView |
||||
contentWidth: width |
||||
contentHeight: childrenRect.height |
||||
anchors.fill: parent |
||||
|
||||
property Item currentItem |
||||
|
||||
Rectangle { |
||||
id: categories |
||||
width: parent.width |
||||
height: Math.max(categoriesView.height, categoriesColumn.height) |
||||
color: syspal.base |
||||
|
||||
Rectangle { |
||||
color: syspal.highlight |
||||
width: parent.width |
||||
height: theme.iconSizes.IconSizeHuge |
||||
y: index * height |
||||
Behavior on y { |
||||
NumberAnimation { |
||||
duration: 250 |
||||
easing.type: "InOutQuad" |
||||
} |
||||
} |
||||
} |
||||
Column { |
||||
id: categoriesColumn |
||||
width: parent.width |
||||
Repeater { |
||||
model: configDialog.configModel |
||||
delegate: ConfigCategoryDelegate { |
||||
onClicked: categoriesView.currentIndex = index |
||||
|
||||
} |
||||
} |
||||
Repeater { |
||||
model: globalConfigModel |
||||
delegate: ConfigCategoryDelegate {} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
QtControls.ScrollView{ |
||||
id: pageScroll |
||||
anchors { |
||||
top: parent.top |
||||
bottom: parent.bottom |
||||
} |
||||
Layout.fillWidth: true |
||||
Flickable { |
||||
contentWidth: width |
||||
contentHeight: main.height |
||||
Item { |
||||
width: parent.width |
||||
height: childrenRect.height |
||||
QtControls.StackView { |
||||
id: main |
||||
anchors.fill: parent |
||||
anchors.margins: 12 |
||||
property string sourceFile |
||||
Timer { |
||||
id: pageSizeSync |
||||
interval: 100 |
||||
onTriggered: { |
||||
// root.width = mainColumn.implicitWidth |
||||
// root.height = mainColumn.implicitHeight |
||||
} |
||||
} |
||||
onImplicitWidthChanged: pageSizeSync.restart() |
||||
onImplicitHeightChanged: pageSizeSync.restart() |
||||
onSourceFileChanged: { |
||||
print("Source file changed in flickable" + sourceFile); |
||||
replace(Qt.resolvedUrl(sourceFile)) |
||||
/* |
||||
* This is not needed on a desktop shell that has ok/apply/cancel buttons, i'll leave it here only for future reference until we have a prototype for the active shell. |
||||
* root.pageChanged will start a timer, that in turn will call saveConfig() when triggered |
||||
|
||||
for (var prop in currentPage) { |
||||
if (prop.indexOf("cfg_") === 0) { |
||||
currentPage[prop+"Changed"].connect(root.pageChanged) |
||||
} |
||||
}*/ |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
RowLayout { |
||||
id: buttonsRow |
||||
anchors { |
||||
right: parent.right |
||||
rightMargin: spacing |
||||
} |
||||
QtControls.Button { |
||||
iconSource: "dialog-ok" |
||||
text: "Ok" |
||||
onClicked: { |
||||
if (main.currentPage.saveConfig !== undefined) { |
||||
main.currentPage.saveConfig() |
||||
} else { |
||||
root.saveConfig() |
||||
} |
||||
configDialog.close() |
||||
} |
||||
} |
||||
QtControls.Button { |
||||
iconSource: "dialog-ok-apply" |
||||
text: "Apply" |
||||
onClicked: { |
||||
if (main.currentPage.saveConfig !== undefined) { |
||||
main.currentPage.saveConfig() |
||||
} else { |
||||
root.saveConfig() |
||||
} |
||||
} |
||||
} |
||||
QtControls.Button { |
||||
iconSource: "dialog-cancel" |
||||
text: "Cancel" |
||||
onClicked: configDialog.close() |
||||
} |
||||
} |
||||
} |
||||
//END UI components |
||||
} |
||||
@ -0,0 +1,81 @@ |
||||
/* |
||||
* Copyright 2013 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
import QtQuick.Controls 1.0 as QtControls |
||||
import org.kde.plasma.core 2.0 as PlasmaCore |
||||
|
||||
MouseArea { |
||||
id: delegate |
||||
|
||||
anchors { |
||||
left: parent.left |
||||
right: parent.right |
||||
} |
||||
//BEGIN properties |
||||
width: childrenRect.width |
||||
height: childrenRect.height |
||||
property bool current: model.source == main.sourceFile |
||||
//END properties |
||||
|
||||
//BEGIN connections |
||||
onClicked: { |
||||
print("model source: " + model.source + " " + main.sourceFile); |
||||
if (delegate.current) { |
||||
return |
||||
} else { |
||||
if (typeof(categoriesView.currentIndex) != "undefined") { |
||||
categoriesView.currentIndex = index; |
||||
} |
||||
main.sourceFile = model.source |
||||
root.restoreConfig() |
||||
} |
||||
} |
||||
onCurrentChanged: { |
||||
if (current) { |
||||
categoriesView.currentIndex = index |
||||
} |
||||
} |
||||
//END connections |
||||
|
||||
//BEGIN UI components |
||||
Column { |
||||
spacing: 4 |
||||
anchors { |
||||
left: parent.left |
||||
right: parent.right |
||||
topMargin: _m |
||||
} |
||||
PlasmaCore.IconItem { |
||||
anchors.horizontalCenter: parent.horizontalCenter |
||||
width: theme.IconSizeHuge |
||||
height: width |
||||
source: model.icon |
||||
} |
||||
QtControls.Label { |
||||
anchors { |
||||
left: parent.left |
||||
right: parent.right |
||||
} |
||||
text: model.name |
||||
wrapMode: Text.Wrap |
||||
horizontalAlignment: Text.AlignHCenter |
||||
} |
||||
} |
||||
//END UI components |
||||
} |
||||
@ -0,0 +1,30 @@ |
||||
/* |
||||
* Copyright 2013 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
import org.kde.plasma.components 2.0 as PlasmaComponents |
||||
|
||||
|
||||
Item { |
||||
implicitWidth: childrenRect.width |
||||
implicitHeight: childrenRect.height |
||||
|
||||
PlasmaComponents.Label { |
||||
text: "Containment actions go here" |
||||
} |
||||
} |
||||
@ -0,0 +1,133 @@ |
||||
/* |
||||
* Copyright 2013 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
import org.kde.plasma.components 2.0 as PlasmaComponents |
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras |
||||
import org.kde.plasma.configuration 2.0 |
||||
import QtQuick.Controls 1.0 as QtControls |
||||
|
||||
Column { |
||||
id: root |
||||
|
||||
spacing: _m |
||||
PlasmaExtras.Title { |
||||
text: "Plugins" |
||||
} |
||||
|
||||
|
||||
//BEGIN functions |
||||
function saveConfig() { |
||||
for (var key in configDialog.wallpaperConfiguration) { |
||||
if (main.currentPage["cfg_"+key] !== undefined) { |
||||
configDialog.wallpaperConfiguration[key] = main.currentPage["cfg_"+key] |
||||
} |
||||
} |
||||
configDialog.applyWallpaper() |
||||
} |
||||
|
||||
function restoreConfig() { |
||||
for (var key in configDialog.wallpaperConfiguration) { |
||||
if (main.currentPage["cfg_"+key] !== undefined) { |
||||
main.currentPage["cfg_"+key] = configDialog.wallpaperConfiguration[key] |
||||
} |
||||
} |
||||
} |
||||
//END functions |
||||
|
||||
ListView { |
||||
id: categoriesView |
||||
anchors { |
||||
left: parent.left |
||||
right: parent.right |
||||
} |
||||
height: 100 |
||||
orientation: ListView.Horizontal |
||||
|
||||
model: configDialog.wallpaperConfigModel |
||||
delegate: ConfigCategoryDelegate { |
||||
id: delegate |
||||
current: categoriesView.currentIndex == index |
||||
anchors { |
||||
top: parent.top |
||||
bottom: parent.bottom |
||||
left: undefined |
||||
right: undefined |
||||
} |
||||
width: 64 |
||||
onClicked: { |
||||
configDialog.currentWallpaper = model.pluginName |
||||
if (categoriesView.currentIndex == index) { |
||||
return |
||||
} else { |
||||
categoriesView.currentIndex = index; |
||||
main.sourceFile = model.source |
||||
root.restoreConfig() |
||||
} |
||||
} |
||||
onCurrentChanged: { |
||||
categoriesView.currentIndex = index |
||||
if (current) { |
||||
categoriesView.currentIndex = index |
||||
} |
||||
} |
||||
Component.onCompleted: { |
||||
if (configDialog.currentWallpaper == model.pluginName) { |
||||
loadWallpaperTimer.pendingCurrent = model |
||||
loadWallpaperTimer.restart() |
||||
} |
||||
} |
||||
} |
||||
highlight: Rectangle { |
||||
color: theme.highlightColor |
||||
} |
||||
Timer { |
||||
id: loadWallpaperTimer |
||||
interval: 100 |
||||
property variant pendingCurrent |
||||
onTriggered: { |
||||
if (pendingCurrent) { |
||||
categoriesView.currentIndex = pendingCurrent.index |
||||
main.sourceFile = pendingCurrent.source |
||||
root.restoreConfig() |
||||
} |
||||
} |
||||
} |
||||
} |
||||
PlasmaComponents.PageStack { |
||||
id: main |
||||
anchors { |
||||
left: categoriesView.left; |
||||
right: parent.right; |
||||
} |
||||
width: implicitWidth |
||||
height: implicitHeight |
||||
property string sourceFile |
||||
onSourceFileChanged: { |
||||
if (sourceFile != "") { |
||||
main.opacity = 1; |
||||
replace(Qt.resolvedUrl(sourceFile)) |
||||
//main.width = mainColumn.implicitWidth |
||||
main.height = mainColumn.implicitHeight |
||||
} else { |
||||
main.opacity = 0 |
||||
} |
||||
} |
||||
Behavior on opacity { NumberAnimation {} } |
||||
} |
||||
} |
||||
@ -0,0 +1,32 @@ |
||||
/* |
||||
* Copyright 2013 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
import org.kde.plasma.components 2.0 as PlasmaComponents |
||||
|
||||
|
||||
Item { |
||||
id: iconsPage |
||||
width: childrenRect.width |
||||
height: childrenRect.height |
||||
|
||||
PlasmaComponents.Button { |
||||
iconSource: "settings" |
||||
text: "None" |
||||
} |
||||
} |
||||
@ -0,0 +1,47 @@ |
||||
/* |
||||
* Copyright 2013 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
import org.kde.plasma.components 2.0 as PlasmaComponents |
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras |
||||
import org.kde.plasma.core 2.0 as PlasmaCore |
||||
import org.kde.plasma.configuration 2.0 |
||||
|
||||
|
||||
AppletConfiguration { |
||||
id: root |
||||
|
||||
//BEGIN model |
||||
globalConfigModel: globalContainmentConfigModel |
||||
|
||||
ConfigModel { |
||||
id: globalContainmentConfigModel |
||||
ConfigCategory { |
||||
name: "Appearance" |
||||
icon: "preferences-desktop-wallpaper" |
||||
source: "ConfigurationContainmentAppearance.qml" |
||||
} |
||||
ConfigCategory { |
||||
name: "Mouse Actions" |
||||
icon: "preferences-desktop-mouse" |
||||
source: "ConfigurationContainmentActions.qml" |
||||
} |
||||
} |
||||
//END model |
||||
|
||||
} |
||||
@ -0,0 +1,186 @@ |
||||
/* |
||||
* Copyright 2013 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
import org.kde.plasma.components 2.0 as PlasmaComponents |
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras |
||||
import org.kde.plasma.core 2.0 as PlasmaCore |
||||
import org.kde.plasma.configuration 2.0 |
||||
import org.kde.qtextracomponents 2.0 as QtExtras |
||||
import "panelconfiguration" |
||||
|
||||
|
||||
//TODO: all of this will be done with desktop components |
||||
PlasmaCore.FrameSvgItem { |
||||
id: dialogRoot |
||||
|
||||
//BEGIN Properties |
||||
width: 640 |
||||
height: 64 |
||||
imagePath: "dialogs/background" |
||||
|
||||
state: { |
||||
switch (panel.location) { |
||||
//TopEdge |
||||
case 3: |
||||
return "TopEdge" |
||||
//LeftEdge |
||||
case 5: |
||||
return "LeftEdge" |
||||
//RightEdge |
||||
case 6: |
||||
return "RightEdge" |
||||
//BottomEdge |
||||
case 4: |
||||
default: |
||||
return "BottomEdge" |
||||
} |
||||
} |
||||
|
||||
property bool vertical: (panel.location == 5 || panel.location == 6) |
||||
//END properties |
||||
|
||||
//BEGIN Connections |
||||
Connections { |
||||
target: panel |
||||
onOffsetChanged: ruler.offset = panel.offset |
||||
onMinimumLengthChanged: ruler.minimumLength = panel.minimumLength |
||||
onMaximumLengthChanged: ruler.maximumLength = panel.maximumLength |
||||
} |
||||
//END Connections |
||||
|
||||
|
||||
//BEGIN UI components |
||||
|
||||
Ruler { |
||||
id: ruler |
||||
state: dialogRoot.state |
||||
} |
||||
|
||||
ToolBar { |
||||
id: toolBar |
||||
} |
||||
//END UI components |
||||
|
||||
//BEGIN Animations |
||||
//when EdgeHandle is released animate to old panel position |
||||
ParallelAnimation { |
||||
id: panelResetAnimation |
||||
NumberAnimation { |
||||
target: panel |
||||
properties: (panel.location == 5 || panel.location == 6) ? "x" : "y" |
||||
to: { |
||||
switch (panel.location) { |
||||
//TopEdge |
||||
case 3: |
||||
return 0 |
||||
break |
||||
//LeftEdge |
||||
case 5: |
||||
return 0 |
||||
break; |
||||
//RightEdge |
||||
case 6: |
||||
return panel.screenGeometry.x + panel.screenGeometry.width - panel.width |
||||
break; |
||||
//BottomEdge |
||||
case 4: |
||||
default: |
||||
return panel.screenGeometry.y + panel.screenGeometry.height - panel.height |
||||
} |
||||
} |
||||
duration: 150 |
||||
} |
||||
NumberAnimation { |
||||
target: configDialog |
||||
properties: (panel.location == 5 || panel.location == 6) ? "x" : "y" |
||||
to: { |
||||
panel.height |
||||
switch (panel.location) { |
||||
//TopEdge |
||||
case 3: |
||||
return panel.height |
||||
break |
||||
//LeftEdge |
||||
case 5: |
||||
return panel.width |
||||
break; |
||||
//RightEdge |
||||
case 6: |
||||
return panel.screenGeometry.x + panel.screenGeometry.width - panel.width - configDialog.width |
||||
break; |
||||
//BottomEdge |
||||
case 4: |
||||
default: |
||||
return panel.screenGeometry.y + panel.screenGeometry.height - panel.height - configDialog.height |
||||
} |
||||
} |
||||
duration: 150 |
||||
} |
||||
} |
||||
//END Animations |
||||
|
||||
//BEGIN States |
||||
states: [ |
||||
State { |
||||
name: "TopEdge" |
||||
PropertyChanges { |
||||
target: dialogRoot |
||||
enabledBorders: "TopBorder|BottomBorder" |
||||
} |
||||
PropertyChanges { |
||||
target: dialogRoot |
||||
implicitHeight: ruler.implicitHeight + toolBar.implicitHeight |
||||
} |
||||
}, |
||||
State { |
||||
name: "BottomEdge" |
||||
PropertyChanges { |
||||
target: dialogRoot |
||||
enabledBorders: "TopBorder|BottomBorder" |
||||
} |
||||
PropertyChanges { |
||||
target: dialogRoot |
||||
implicitHeight: ruler.implicitHeight + toolBar.implicitHeight |
||||
} |
||||
}, |
||||
State { |
||||
name: "LeftEdge" |
||||
PropertyChanges { |
||||
target: dialogRoot |
||||
enabledBorders: "LeftBorder|RightBorder" |
||||
} |
||||
PropertyChanges { |
||||
target: dialogRoot |
||||
implicitWidth: ruler.implicitWidth + toolBar.implicitWidth |
||||
} |
||||
}, |
||||
State { |
||||
name: "RightEdge" |
||||
PropertyChanges { |
||||
target: dialogRoot |
||||
enabledBorders: "LeftBorder|RightBorder" |
||||
} |
||||
PropertyChanges { |
||||
target: dialogRoot |
||||
implicitWidth: ruler.implicitWidth + toolBar.implicitWidth |
||||
} |
||||
} |
||||
] |
||||
//END States |
||||
} |
||||
@ -0,0 +1,112 @@ |
||||
/* |
||||
* Copyright 2013 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
import org.kde.plasma.components 2.0 as PlasmaComponents |
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras |
||||
import org.kde.plasma.core 2.0 as PlasmaCore |
||||
import org.kde.plasma.configuration 2.0 |
||||
import org.kde.qtextracomponents 2.0 as QtExtras |
||||
|
||||
PlasmaComponents.ToolButton { |
||||
flat: false |
||||
text: "Screen edge" |
||||
|
||||
QtExtras.MouseEventListener { |
||||
anchors.fill: parent |
||||
property int lastX |
||||
property int lastY |
||||
property int startMouseX |
||||
property int startMouseY |
||||
onPressed: { |
||||
lastX = mouse.screenX |
||||
lastY = mouse.screenY |
||||
startMouseX = mouse.x |
||||
startMouseY = mouse.y |
||||
} |
||||
onPositionChanged: { |
||||
switch (panel.location) { |
||||
//TopEdge |
||||
case 3: |
||||
configDialog.y = mouse.screenY - mapToItem(dialogRoot, 0, startMouseY).y |
||||
panel.y = configDialog.y - panel.height |
||||
break |
||||
//LeftEdge |
||||
case 5: |
||||
configDialog.x = mouse.screenX - mapToItem(dialogRoot, startMouseX, 0).x |
||||
panel.x = configDialog.x - panel.width |
||||
break; |
||||
//RightEdge |
||||
case 6: |
||||
configDialog.x = mouse.screenX - mapToItem(dialogRoot, startMouseX, 0).x |
||||
panel.x = configDialog.x + configDialog.width |
||||
break; |
||||
//BottomEdge |
||||
case 4: |
||||
default: |
||||
configDialog.y = mouse.screenY - mapToItem(dialogRoot, 0, startMouseY).y |
||||
panel.y = configDialog.y + configDialog.height |
||||
} |
||||
|
||||
lastX = mouse.screenX |
||||
lastY = mouse.screenY |
||||
|
||||
var screenAspect = panel.screenGeometry.height / panel.screenGeometry.width |
||||
var newLocation = panel.location |
||||
|
||||
//If the mouse is in an internal rectangle, do nothing |
||||
if ((mouse.screenX > panel.screenGeometry.x + panel.screenGeometry.width/3 && |
||||
mouse.screenX < panel.screenGeometry.x + panel.screenGeometry.width/3*2) && |
||||
(mouse.screenY > panel.screenGeometry.y + panel.screenGeometry.height/3 && |
||||
mouse.screenY < panel.screenGeometry.y + panel.screenGeometry.height/3*2)) { |
||||
return; |
||||
} |
||||
|
||||
|
||||
if (mouse.screenY < panel.screenGeometry.y+(mouse.screenX-panel.screenGeometry.x)*screenAspect) { |
||||
if (mouse.screenY < panel.screenGeometry.y + panel.screenGeometry.height-(mouse.screenX-panel.screenGeometry.x)*screenAspect) { |
||||
if (panel.location == 3) { |
||||
return; |
||||
} else { |
||||
newLocation = 3; //FIXME: Plasma::TopEdge; |
||||
} |
||||
} else if (panel.location == 6) { |
||||
return; |
||||
} else { |
||||
newLocation = 6; //FIXME: Plasma::RightEdge; |
||||
} |
||||
|
||||
} else { |
||||
if (mouse.screenY < panel.screenGeometry.y + panel.screenGeometry.height-(mouse.screenX-panel.screenGeometry.x)*screenAspect) { |
||||
if (panel.location == 5) { |
||||
return; |
||||
} else { |
||||
newLocation = 5; //FIXME: Plasma::LeftEdge; |
||||
} |
||||
} else if(panel.location == 4) { |
||||
return; |
||||
} else { |
||||
newLocation = 4; //FIXME: Plasma::BottomEdge; |
||||
} |
||||
} |
||||
panel.location = newLocation |
||||
print("New Location: " + newLocation); |
||||
} |
||||
onReleased: panelResetAnimation.running = true |
||||
} |
||||
} |
||||
@ -0,0 +1,352 @@ |
||||
/* |
||||
* Copyright 2013 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
import org.kde.plasma.components 2.0 as PlasmaComponents |
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras |
||||
import org.kde.plasma.core 2.0 as PlasmaCore |
||||
import org.kde.plasma.configuration 2.0 |
||||
import org.kde.qtextracomponents 2.0 as QtExtras |
||||
|
||||
|
||||
PlasmaCore.FrameSvgItem { |
||||
id: root |
||||
|
||||
property alias offset: offsetHandle.value |
||||
property alias minimumLength: minimumLengthHandle.value |
||||
property alias maximumLength: maximumLengthHandle.value |
||||
|
||||
imagePath: "widgets/containment-controls" |
||||
state: "BottomEdge" |
||||
implicitWidth: offsetHandle.width + minimumLengthHandle.width |
||||
implicitHeight: offsetHandle.height + minimumLengthHandle.height |
||||
|
||||
onMinimumLengthChanged: leftMinimumLengthHandle.value = minimumLength |
||||
onMaximumLengthChanged: leftMaximumLengthHandle.value = maximumLength |
||||
|
||||
Component.onCompleted: { |
||||
offsetHandle.value = panel.offset |
||||
minimumLengthHandle.value = panel.minimumLength |
||||
maximumLengthHandle.value = panel.maximumLength |
||||
leftMinimumLengthHandle.value = panel.minimumLength |
||||
leftMaximumLengthHandle.value = panel.maximumLength |
||||
} |
||||
|
||||
PlasmaCore.Svg { |
||||
id: containmentControlsSvg |
||||
imagePath: "widgets/containment-controls" |
||||
} |
||||
PlasmaCore.SvgItem { |
||||
id: centerMark |
||||
svg: containmentControlsSvg |
||||
elementId: dialogRoot.vertical ? "vertical-centerindicator" : "horizontal-centerindicator" |
||||
visible: panel.alignment == Qt.AlignCenter |
||||
width: dialogRoot.vertical ? parent.width : naturalSize.width |
||||
height: dialogRoot.vertical ? naturalSize.height : parent.height |
||||
anchors.centerIn: parent |
||||
} |
||||
|
||||
SliderHandle { |
||||
id: offsetHandle |
||||
graphicElementName: "offsetslider" |
||||
onValueChanged: panel.offset = value |
||||
} |
||||
SliderHandle { |
||||
id: minimumLengthHandle |
||||
alignment: panel.alignment | Qt.AlignLeft |
||||
visible: panel.alignment != Qt.AlignRight |
||||
offset: panel.offset |
||||
graphicElementName: "minslider" |
||||
onValueChanged: panel.minimumLength = value |
||||
} |
||||
SliderHandle { |
||||
id: maximumLengthHandle |
||||
alignment: panel.alignment | Qt.AlignLeft |
||||
visible: panel.alignment != Qt.AlignRight |
||||
offset: panel.offset |
||||
graphicElementName: "maxslider" |
||||
onValueChanged: panel.maximumLength = value |
||||
} |
||||
SliderHandle { |
||||
id: leftMinimumLengthHandle |
||||
alignment: panel.alignment | Qt.AlignRight |
||||
visible: panel.alignment != Qt.AlignLeft |
||||
offset: panel.offset |
||||
graphicElementName: "maxslider" |
||||
onValueChanged: panel.minimumLength = value |
||||
} |
||||
SliderHandle { |
||||
id: leftMaximumLengthHandle |
||||
alignment: panel.alignment | Qt.AlignRight |
||||
visible: panel.alignment != Qt.AlignLeft |
||||
offset: panel.offset |
||||
graphicElementName: "minslider" |
||||
onValueChanged: panel.maximumLength = value |
||||
} |
||||
|
||||
states: [ |
||||
State { |
||||
name: "TopEdge" |
||||
PropertyChanges { |
||||
target: root |
||||
prefix: "north" |
||||
height: root.implicitHeight |
||||
} |
||||
AnchorChanges { |
||||
target: root |
||||
anchors { |
||||
top: root.parent.top |
||||
bottom: undefined |
||||
left: root.parent.left |
||||
right: root.parent.right |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: offsetHandle |
||||
anchors { |
||||
top: undefined |
||||
bottom: root.bottom |
||||
left: undefined |
||||
right: undefined |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: minimumLengthHandle |
||||
anchors { |
||||
top: root.top |
||||
bottom: undefined |
||||
left: undefined |
||||
right: undefined |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: maximumLengthHandle |
||||
anchors { |
||||
top: undefined |
||||
bottom: root.bottom |
||||
left: undefined |
||||
right: undefined |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: leftMinimumLengthHandle |
||||
anchors { |
||||
top: root.top |
||||
bottom: undefined |
||||
left: undefined |
||||
right: undefined |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: leftMaximumLengthHandle |
||||
anchors { |
||||
top: undefined |
||||
bottom: root.bottom |
||||
left: undefined |
||||
right: undefined |
||||
} |
||||
} |
||||
}, |
||||
State { |
||||
name: "BottomEdge" |
||||
PropertyChanges { |
||||
target: root |
||||
prefix: "south" |
||||
height: root.implicitHeight |
||||
} |
||||
AnchorChanges { |
||||
target: root |
||||
anchors { |
||||
top: undefined |
||||
bottom: root.parent.bottom |
||||
left: root.parent.left |
||||
right: root.parent.right |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: offsetHandle |
||||
anchors { |
||||
top: root.top |
||||
bottom: undefined |
||||
left: undefined |
||||
right: undefined |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: minimumLengthHandle |
||||
anchors { |
||||
top: undefined |
||||
bottom: root.bottom |
||||
left: undefined |
||||
right: undefined |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: maximumLengthHandle |
||||
anchors { |
||||
top: root.top |
||||
bottom: undefined |
||||
left: undefined |
||||
right: undefined |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: leftMinimumLengthHandle |
||||
anchors { |
||||
top: undefined |
||||
bottom: root.bottom |
||||
left: undefined |
||||
right: undefined |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: leftMaximumLengthHandle |
||||
anchors { |
||||
top: root.top |
||||
bottom: undefined |
||||
left: undefined |
||||
right: undefined |
||||
} |
||||
} |
||||
}, |
||||
State { |
||||
name: "LeftEdge" |
||||
PropertyChanges { |
||||
target: root |
||||
prefix: "west" |
||||
width: root.implicitWidth |
||||
} |
||||
AnchorChanges { |
||||
target: root |
||||
anchors { |
||||
top: root.parent.top |
||||
bottom: root.parent.bottom |
||||
left: root.parent.left |
||||
right: undefined |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: offsetHandle |
||||
anchors { |
||||
top: undefined |
||||
bottom: undefined |
||||
left: undefined |
||||
right: root.right |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: minimumLengthHandle |
||||
anchors { |
||||
top: undefined |
||||
bottom: undefined |
||||
left: root.left |
||||
right: undefined |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: maximumLengthHandle |
||||
anchors { |
||||
top: undefined |
||||
bottom: undefined |
||||
left: undefined |
||||
right: root.right |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: leftMinimumLengthHandle |
||||
anchors { |
||||
top: undefined |
||||
bottom: undefined |
||||
left: root.left |
||||
right: undefined |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: leftMaximumLengthHandle |
||||
anchors { |
||||
top: undefined |
||||
bottom: undefined |
||||
left: undefined |
||||
right: root.right |
||||
} |
||||
} |
||||
}, |
||||
State { |
||||
name: "RightEdge" |
||||
PropertyChanges { |
||||
target: root |
||||
prefix: "east" |
||||
width: root.implicitWidth |
||||
} |
||||
AnchorChanges { |
||||
target: root |
||||
anchors { |
||||
top: root.parent.top |
||||
bottom: root.parent.bottom |
||||
left: undefined |
||||
right: root.parent.right |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: offsetHandle |
||||
anchors { |
||||
top: undefined |
||||
bottom: undefined |
||||
left: parent.left |
||||
right: undefined |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: minimumLengthHandle |
||||
anchors { |
||||
top: undefined |
||||
bottom: undefined |
||||
left: undefined |
||||
right: parent.right |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: maximumLengthHandle |
||||
anchors { |
||||
top: undefined |
||||
bottom: undefined |
||||
left: parent.left |
||||
right: undefined |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: leftMinimumLengthHandle |
||||
anchors { |
||||
top: undefined |
||||
bottom: undefined |
||||
left: undefined |
||||
right: parent.right |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: leftMaximumLengthHandle |
||||
anchors { |
||||
top: undefined |
||||
bottom: undefined |
||||
left: parent.left |
||||
right: undefined |
||||
} |
||||
} |
||||
} |
||||
] |
||||
} |
||||
@ -0,0 +1,62 @@ |
||||
/* |
||||
* Copyright 2013 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
import org.kde.plasma.components 2.0 as PlasmaComponents |
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras |
||||
import org.kde.plasma.core 2.0 as PlasmaCore |
||||
import org.kde.plasma.configuration 2.0 |
||||
import org.kde.qtextracomponents 2.0 as QtExtras |
||||
|
||||
PlasmaComponents.ToolButton { |
||||
flat: false |
||||
text: "Height" |
||||
QtExtras.MouseEventListener { |
||||
anchors.fill: parent |
||||
property int startMouseX |
||||
property int startMouseY |
||||
onPressed: { |
||||
startMouseX = mouse.x |
||||
startMouseY = mouse.y |
||||
} |
||||
onPositionChanged: { |
||||
switch (panel.location) { |
||||
//TopEdge |
||||
case 3: |
||||
configDialog.y = mouse.screenY - mapToItem(dialogRoot, 0, startMouseY).y |
||||
panel.thickness = configDialog.y - panel.y |
||||
break; |
||||
//LeftEdge |
||||
case 5: |
||||
configDialog.x = mouse.screenX - mapToItem(dialogRoot, startMouseX, 0).x |
||||
panel.thickness = configDialog.x - panel.x |
||||
break; |
||||
//RightEdge |
||||
case 6: |
||||
configDialog.x = mouse.screenX - mapToItem(dialogRoot, startMouseX, 0).x |
||||
panel.thickness = (panel.x + panel.width) - (configDialog.x + configDialog.width) |
||||
break; |
||||
//BottomEdge |
||||
case 4: |
||||
default: |
||||
configDialog.y = mouse.screenY - mapToItem(dialogRoot, 0, startMouseY).y |
||||
panel.thickness = (panel.y + panel.height) - (configDialog.y + configDialog.height) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,166 @@ |
||||
/* |
||||
* Copyright 2013 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
import org.kde.plasma.components 2.0 as PlasmaComponents |
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras |
||||
import org.kde.plasma.core 2.0 as PlasmaCore |
||||
import org.kde.plasma.configuration 2.0 |
||||
import org.kde.qtextracomponents 2.0 as QtExtras |
||||
|
||||
|
||||
PlasmaCore.SvgItem { |
||||
id: root |
||||
svg: containmentControlsSvg |
||||
state: parent.state |
||||
width: naturalSize.width |
||||
height: naturalSize.height |
||||
|
||||
//value expressed by this slider |
||||
property int value |
||||
//name of the graphics to load |
||||
property string graphicElementName |
||||
//where the point "0" is |
||||
property int offset: 0 |
||||
//handle type: behave in different ways based on the alignment |
||||
property int alignment: panel.alignment |
||||
|
||||
function syncPos() { |
||||
if (dialogRoot.vertical) { |
||||
if (alignment == Qt.AlignRight) { |
||||
y = root.parent.height - (value + offset + root.height/2) |
||||
} else if (alignment == Qt.AlignLeft) { |
||||
y = value + offset - root.height/2 |
||||
} else { |
||||
if (root.alignment & Qt.AlignRight) { |
||||
y = root.parent.height/2 - value/2 - offset + root.height/2 |
||||
} else if (root.alignment & Qt.AlignLeft) { |
||||
y = root.parent.height/2 + value/2 + offset - root.height/2 |
||||
} else { |
||||
y = root.parent.height/2 + value + offset -root.height/2 |
||||
} |
||||
} |
||||
} else { |
||||
if (alignment == Qt.AlignRight) { |
||||
x = root.parent.width - (value + offset + root.width/2) |
||||
} else if (alignment == Qt.AlignLeft) { |
||||
x = value + offset - root.width/2 |
||||
} else { |
||||
if (root.alignment & Qt.AlignRight) { |
||||
x = root.parent.width/2 - value/2 + offset - root.width/2 |
||||
} else if (root.alignment & Qt.AlignLeft) { |
||||
x = root.parent.width/2 + value/2 + offset -root.width/2 |
||||
} else { |
||||
x = root.parent.width/2 + value + offset -root.width/2 |
||||
} |
||||
} |
||||
} |
||||
} |
||||
onValueChanged: syncPos() |
||||
onOffsetChanged: syncPos() |
||||
onAlignmentChanged: syncPos() |
||||
Connections { |
||||
target: root.parent |
||||
onWidthChanged: syncPos() |
||||
onHeightChanged: syncPos() |
||||
} |
||||
|
||||
MouseArea { |
||||
drag { |
||||
target: parent |
||||
axis: (dialogRoot.vertical) ? Drag.YAxis : Drag.XAxis |
||||
} |
||||
anchors.fill: parent |
||||
onPositionChanged: { |
||||
if (dialogRoot.vertical) { |
||||
if (root.alignment == Qt.AlignRight) { |
||||
root.value = root.parent.height - (parent.y + offset + root.height/2) |
||||
} else if (alignment == Qt.AlignLeft) { |
||||
root.value = parent.y - offset + root.height/2 |
||||
//Center |
||||
} else { |
||||
if (root.alignment & Qt.AlignRight) { |
||||
root.value = (root.parent.height/2 - parent.y + offset)*2 + root.height/2 |
||||
} else if (root.alignment & Qt.AlignLeft) { |
||||
root.value = (parent.y - offset - root.parent.height/2)*2 + root.height/2 |
||||
} else { |
||||
var value = parent.y - root.parent.height/2 - offset + root.height/2 |
||||
//Snap |
||||
if (Math.abs(value) < 5) { |
||||
root.value = 0 |
||||
} else { |
||||
root.value = value |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
if (root.alignment == Qt.AlignRight) { |
||||
root.value = root.parent.width - (parent.x + offset + root.width/2) |
||||
} else if (alignment == Qt.AlignLeft) { |
||||
root.value = parent.x - offset + root.width/2 |
||||
//Center |
||||
} else { |
||||
if (root.alignment & Qt.AlignRight) { |
||||
root.value = (root.parent.width/2 - parent.x + offset)*2 + root.width/2 |
||||
} else if (root.alignment & Qt.AlignLeft) { |
||||
root.value = (parent.x - offset - root.parent.width/2)*2 + root.width/2 |
||||
} else { |
||||
var value = parent.x - root.parent.width/2 - offset + root.width/2 |
||||
//Snap |
||||
if (Math.abs(value) < 5) { |
||||
root.value = 0 |
||||
} else { |
||||
root.value = value |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
states: [ |
||||
State { |
||||
name: "TopEdge" |
||||
PropertyChanges { |
||||
target: root |
||||
elementId: "north-" + graphicElementName |
||||
} |
||||
}, |
||||
State { |
||||
name: "BottomEdge" |
||||
PropertyChanges { |
||||
target: root |
||||
elementId: "south-" + graphicElementName |
||||
} |
||||
}, |
||||
State { |
||||
name: "LeftEdge" |
||||
PropertyChanges { |
||||
target: root |
||||
elementId: "west-" + graphicElementName |
||||
} |
||||
}, |
||||
State { |
||||
name: "RightEdge" |
||||
PropertyChanges { |
||||
target: root |
||||
elementId: "east-" + graphicElementName |
||||
} |
||||
} |
||||
] |
||||
} |
||||
@ -0,0 +1,232 @@ |
||||
/* |
||||
* Copyright 2013 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
import org.kde.plasma.components 2.0 as PlasmaComponents |
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras |
||||
import org.kde.plasma.core 2.0 as PlasmaCore |
||||
import org.kde.plasma.configuration 2.0 |
||||
|
||||
Item { |
||||
id: root |
||||
state: parent.state |
||||
implicitWidth: childrenRect.width + 20 |
||||
implicitHeight: childrenRect.height + 20 |
||||
PlasmaComponents.ButtonRow { |
||||
id: row |
||||
spacing: 0 |
||||
exclusive: false |
||||
visible: !dialogRoot.vertical |
||||
anchors { |
||||
centerIn: parent |
||||
} |
||||
EdgeHandle { |
||||
id: edgeHandle |
||||
} |
||||
SizeHandle { |
||||
id: sizeHandle |
||||
} |
||||
} |
||||
//FIXME: remove this duplication, use desktopcomponents linear layouts that can switch between horizontal and vertical |
||||
PlasmaComponents.ButtonColumn { |
||||
id: column |
||||
spacing: 0 |
||||
exclusive: false |
||||
visible: dialogRoot.vertical |
||||
anchors { |
||||
centerIn: parent |
||||
} |
||||
EdgeHandle { |
||||
width: 80 |
||||
} |
||||
SizeHandle { |
||||
width: 80 |
||||
} |
||||
} |
||||
|
||||
PlasmaComponents.Button { |
||||
id: moreSettingsButton |
||||
property QtObject contextMenu |
||||
text: "More settings" |
||||
onClicked: { |
||||
if (!contextMenu) { |
||||
contextMenu = contextMenuComponent.createObject(moreSettingsButton) |
||||
} |
||||
contextMenu.open() |
||||
} |
||||
} |
||||
|
||||
Component { |
||||
id: contextMenuComponent |
||||
PlasmaComponents.ContextMenu { |
||||
visualParent: moreSettingsButton |
||||
PlasmaComponents.MenuItem { |
||||
id: leftToggle |
||||
text: "Left" |
||||
checkable: true |
||||
checked: panel.alignment == Qt.AlignLeft |
||||
onClicked: panel.alignment = Qt.AlignLeft |
||||
onToggled: { |
||||
if (checked) { |
||||
centerToggle.checked = false |
||||
rightToggle.checked = false |
||||
} |
||||
} |
||||
} |
||||
PlasmaComponents.MenuItem { |
||||
id: centerToggle |
||||
text: "Center" |
||||
checkable: true |
||||
checked: panel.alignment == Qt.AlignCenter |
||||
onClicked: panel.alignment = Qt.AlignCenter |
||||
onToggled: { |
||||
if (checked) { |
||||
leftToggle.checked = false |
||||
rightToggle.checked = false |
||||
} |
||||
} |
||||
} |
||||
PlasmaComponents.MenuItem { |
||||
id: rightToggle |
||||
text: "Right" |
||||
checkable: true |
||||
checked: panel.alignment == Qt.AlignRight |
||||
onClicked: panel.alignment = Qt.AlignRight |
||||
onToggled: { |
||||
if (checked) { |
||||
centerToggle.checked = false |
||||
leftToggle.checked = false |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
//BEGIN States |
||||
states: [ |
||||
State { |
||||
name: "TopEdge" |
||||
PropertyChanges { |
||||
target: root |
||||
height: root.implicitHeight |
||||
} |
||||
AnchorChanges { |
||||
target: root |
||||
anchors { |
||||
top: undefined |
||||
bottom: root.parent.bottom |
||||
left: root.parent.left |
||||
right: root.parent.right |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: moreSettingsButton |
||||
anchors { |
||||
verticalCenter: root.verticalCenter |
||||
horizontalCenter: undefined |
||||
top: undefined |
||||
bottom: undefined |
||||
left: undefined |
||||
right: root.right |
||||
} |
||||
} |
||||
}, |
||||
State { |
||||
name: "BottomEdge" |
||||
PropertyChanges { |
||||
target: root |
||||
height: root.implicitHeight |
||||
} |
||||
AnchorChanges { |
||||
target: root |
||||
anchors { |
||||
top: root.parent.top |
||||
bottom: undefined |
||||
left: root.parent.left |
||||
right: root.parent.right |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: moreSettingsButton |
||||
anchors { |
||||
verticalCenter: root.verticalCenter |
||||
horizontalCenter: undefined |
||||
top: undefined |
||||
bottom: undefined |
||||
left: undefined |
||||
right: root.right |
||||
} |
||||
} |
||||
}, |
||||
State { |
||||
name: "LeftEdge" |
||||
PropertyChanges { |
||||
target: root |
||||
width: root.implicitWidth |
||||
} |
||||
AnchorChanges { |
||||
target: root |
||||
anchors { |
||||
top: root.parent.top |
||||
bottom: root.parent.bottom |
||||
left: undefined |
||||
right: root.parent.right |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: moreSettingsButton |
||||
anchors { |
||||
verticalCenter: undefined |
||||
horizontalCenter: root.verticalCenter |
||||
top: undefined |
||||
bottom: root.bottom |
||||
left: undefined |
||||
right: undefined |
||||
} |
||||
} |
||||
}, |
||||
State { |
||||
name: "RightEdge" |
||||
PropertyChanges { |
||||
target: root |
||||
width: root.implicitWidth |
||||
} |
||||
AnchorChanges { |
||||
target: root |
||||
anchors { |
||||
top: root.parent.top |
||||
bottom: root.parent.bottom |
||||
left: root.parent.left |
||||
right: undefined |
||||
} |
||||
} |
||||
AnchorChanges { |
||||
target: moreSettingsButton |
||||
anchors { |
||||
verticalCenter: undefined |
||||
horizontalCenter: root.verticalCenter |
||||
top: undefined |
||||
bottom: root.bottom |
||||
left: undefined |
||||
right: undefined |
||||
} |
||||
} |
||||
} |
||||
] |
||||
//END States |
||||
} |
||||
@ -0,0 +1,17 @@ |
||||
[Desktop] |
||||
Containment=org.kde.desktop |
||||
ToolBox=org.kde.toolbox |
||||
RuntimePlatform= |
||||
|
||||
[Desktop][ContainmentActions] |
||||
Ctrl;LeftButton=org.kde.standardmenu |
||||
MiddleButton=org.kde.paste |
||||
|
||||
[Panel] |
||||
Containment=org.kde.panel |
||||
ToolBox=org.kde.paneltoolbox |
||||
[Panel][ContainmentActions] |
||||
Ctrl;LeftButton=org.kde.standardmenu |
||||
|
||||
[Theme] |
||||
Theme=default |
||||
@ -0,0 +1,197 @@ |
||||
/* |
||||
* Copyright 2011 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU Library General Public License as |
||||
* published by the Free Software Foundation; either version 2 or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details |
||||
* |
||||
* You should have received a copy of the GNU Library General Public |
||||
* License along with this program; if not, write to the |
||||
* Free Software Foundation, Inc., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
import org.kde.plasma.components 2.0 as PlasmaComponents |
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras |
||||
import org.kde.plasma.core 2.0 as PlasmaCore |
||||
import org.kde.draganddrop 2.0 |
||||
import org.kde.qtextracomponents 2.0 |
||||
|
||||
PlasmaCore.FrameSvgItem { |
||||
id: background |
||||
width: list.delegateWidth |
||||
height: list.delegateHeight |
||||
|
||||
property variant icon: decoration |
||||
property string title: name |
||||
property string description: model.description |
||||
property string author: model.author |
||||
property string email: model.email |
||||
property string license: model.license |
||||
property string pluginName: model.pluginName |
||||
property bool local: model.local |
||||
|
||||
ListView.onRemove: SequentialAnimation { |
||||
PropertyAction { |
||||
target: background |
||||
property: "ListView.delayRemove" |
||||
value: true |
||||
} |
||||
NumberAnimation { |
||||
target: background |
||||
property: widgetExplorer.orientation == Qt.Horizontal ? "y" : "x" |
||||
to: widgetExplorer.orientation == Qt.Horizontal ? list.delegateHeight : list.delegateWidth |
||||
duration: 150 |
||||
easing.type: Easing.InOutQuad |
||||
} |
||||
NumberAnimation { |
||||
target: background |
||||
property: widgetExplorer.orientation == Qt.Horizontal ? "y" : "x" |
||||
to: widgetExplorer.orientation == Qt.Horizontal ? list.delegateHeight : list.delegateWidth |
||||
duration: 150 |
||||
easing.type: Easing.InOutQuad |
||||
} |
||||
NumberAnimation { |
||||
target: background |
||||
property: widgetExplorer.orientation == Qt.Horizontal ? "width" : "height" |
||||
from: widgetExplorer.orientation == Qt.Horizontal ? list.delegateWidth : list.delegateHeight |
||||
to: 0 |
||||
duration: 150 |
||||
easing.type: Easing.InOutQuad |
||||
} |
||||
PropertyAction { |
||||
target: background |
||||
property: "ListView.delayRemove" |
||||
value: false |
||||
} |
||||
} |
||||
|
||||
ListView.onAdd: SequentialAnimation { |
||||
PropertyAction { |
||||
target: background |
||||
property: "y" |
||||
value: widgetExplorer.orientation == Qt.Horizontal ? -list.delegateHeight : -list.delegateWidth |
||||
} |
||||
NumberAnimation { |
||||
target: background |
||||
property: widgetExplorer.orientation == Qt.Horizontal ? "width" : "height" |
||||
from: 0 |
||||
to: widgetExplorer.orientation == Qt.Horizontal ? list.delegateWidth : list.delegateHeight |
||||
duration: 150 |
||||
easing.type: Easing.InOutQuad |
||||
} |
||||
NumberAnimation { |
||||
target: background |
||||
property: widgetExplorer.orientation == Qt.Horizontal ? "y" : "x" |
||||
to: 0 |
||||
duration: 150 |
||||
easing.type: Easing.InOutQuad |
||||
} |
||||
} |
||||
|
||||
|
||||
imagePath: "widgets/viewitem" |
||||
prefix: "normal" |
||||
|
||||
DragArea { |
||||
anchors.fill: parent |
||||
supportedActions: Qt.MoveAction | Qt.LinkAction |
||||
onDragStarted: tooltipDialog.visible = false |
||||
delegateImage: background.icon |
||||
mimeData { |
||||
source: parent |
||||
} |
||||
Component.onCompleted: mimeData.setData("text/x-plasmoidservicename", pluginName) |
||||
|
||||
QIconItem { |
||||
id: iconWidget |
||||
anchors.verticalCenter: parent.verticalCenter |
||||
x: y |
||||
width: theme.hugeIconSize |
||||
height: width |
||||
icon: background.icon |
||||
} |
||||
Column { |
||||
anchors { |
||||
left: iconWidget.right |
||||
right: parent.right |
||||
verticalCenter: parent.verticalCenter |
||||
|
||||
leftMargin: background.margins.left |
||||
rightMargin: background.margins.right |
||||
} |
||||
spacing: 4 |
||||
PlasmaExtras.Heading { |
||||
id: titleText |
||||
level: 4 |
||||
text: title |
||||
// font { |
||||
// weight: Font.Bold |
||||
// pointSize: theme.smallestFont.pointSize |
||||
// } |
||||
anchors { |
||||
left: parent.left |
||||
right: parent.right |
||||
} |
||||
height: paintedHeight |
||||
wrapMode: Text.WordWrap |
||||
//go with nowrap only if there is a single word too long |
||||
onPaintedWidthChanged: { |
||||
wrapTimer.restart() |
||||
} |
||||
Timer { |
||||
id: wrapTimer |
||||
interval: 200 |
||||
onTriggered: { |
||||
//give it some pixels of tolerance |
||||
if (titleText.paintedWidth > titleText.width + 3) { |
||||
titleText.wrapMode = Text.NoWrap |
||||
titleText.elide = Text.ElideRight |
||||
} else { |
||||
titleText.wrapMode = Text.WordWrap |
||||
titleText.elide = Text.ElideNone |
||||
} |
||||
} |
||||
} |
||||
} |
||||
PlasmaComponents.Label { |
||||
text: description |
||||
font.pointSize: theme.smallestFont.pointSize |
||||
anchors { |
||||
left: parent.left |
||||
right: parent.right |
||||
} |
||||
//elide: Text.ElideRight |
||||
wrapMode: Text.WordWrap |
||||
verticalAlignment: Text.AlignTop |
||||
maximumLineCount: 3 |
||||
} |
||||
} |
||||
QIconItem { |
||||
icon: running ? "dialog-ok-apply" : undefined |
||||
visible: running |
||||
width: theme.smallIconSize |
||||
height: width |
||||
anchors { |
||||
right: parent.right |
||||
bottom: parent.bottom |
||||
rightMargin: background.margins.right |
||||
bottomMargin: background.margins.bottom |
||||
} |
||||
} |
||||
MouseArea { |
||||
anchors.fill: parent |
||||
hoverEnabled: true |
||||
onDoubleClicked: widgetExplorer.addApplet(pluginName) |
||||
onEntered: tooltipDialog.appletDelegate = background |
||||
onExited: tooltipDialog.appletDelegate = null |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,51 @@ |
||||
/* |
||||
* Copyright 2013 Sebastian Kügler <sebas@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
//import org.kde.plasma.core 2.0 as PlasmaCore |
||||
//import org.kde.plasma.components 2.0 as PlasmaComponents |
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras |
||||
|
||||
|
||||
Rectangle { |
||||
id: root |
||||
color: "pink" |
||||
width: 400 |
||||
height: 800 |
||||
|
||||
ListView { |
||||
anchors.fill: parent |
||||
model: widgetExplorer.widgetsModel |
||||
header: PlasmaExtras.Title { text: "Add Widgets" } |
||||
delegate: Item { |
||||
width: parent.width |
||||
height: 48 |
||||
Text { text: "Applet: " + pluginName } |
||||
|
||||
MouseArea { |
||||
anchors.fill: parent |
||||
onClicked: widgetExplorer.addApplet(pluginName) |
||||
} |
||||
} |
||||
} |
||||
|
||||
Component.onCompleted: { |
||||
print("WidgetExplorer QML loaded"); |
||||
print(" found " + widgetExplorer.widgetsModel.count + " widgets"); |
||||
} |
||||
} |
||||
@ -0,0 +1,142 @@ |
||||
/* |
||||
* Copyright 2011 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU Library General Public License as |
||||
* published by the Free Software Foundation; either version 2 or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details |
||||
* |
||||
* You should have received a copy of the GNU Library General Public |
||||
* License along with this program; if not, write to the |
||||
* Free Software Foundation, Inc., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
import org.kde.plasma.components 2.0 as PlasmaComponents |
||||
import org.kde.plasma.core 2.0 as PlasmaCore |
||||
import org.kde.qtextracomponents 2.0 |
||||
|
||||
MouseArea { |
||||
id: main |
||||
|
||||
hoverEnabled: true |
||||
onEntered: toolTipHideTimer.running = false |
||||
onExited: toolTipHideTimer.running = true |
||||
|
||||
width: childrenRect.width |
||||
height: 200 |
||||
|
||||
property variant icon |
||||
property string title |
||||
property string description |
||||
property string author |
||||
property string email |
||||
property string license |
||||
property string pluginName |
||||
property bool local |
||||
|
||||
onClicked: tooltipDialog.visible = false |
||||
Connections { |
||||
target: tooltipDialog |
||||
onAppletDelegateChanged: { |
||||
if (!tooltipDialog.appletDelegate) { |
||||
return |
||||
} |
||||
icon = tooltipDialog.appletDelegate.icon |
||||
title = tooltipDialog.appletDelegate.title |
||||
description = tooltipDialog.appletDelegate.description |
||||
author = tooltipDialog.appletDelegate.author |
||||
email = tooltipDialog.appletDelegate.email |
||||
license = tooltipDialog.appletDelegate.license |
||||
pluginName = tooltipDialog.appletDelegate.pluginName |
||||
local = tooltipDialog.appletDelegate.local |
||||
} |
||||
} |
||||
QIconItem { |
||||
id: tooltipIconWidget |
||||
anchors.left: parent.left |
||||
anchors.top: parent.top |
||||
width: theme.hugeIconSize |
||||
height: width |
||||
icon: main.icon |
||||
} |
||||
Column { |
||||
id: nameColumn |
||||
spacing: 8 |
||||
anchors { |
||||
left: tooltipIconWidget.right |
||||
leftMargin: 8 |
||||
top: parent.top |
||||
right: parent.right |
||||
} |
||||
|
||||
PlasmaComponents.Label { |
||||
text: title |
||||
font.bold:true |
||||
anchors.left: parent.left |
||||
anchors.right: parent.right |
||||
height: paintedHeight |
||||
wrapMode: Text.Wrap |
||||
} |
||||
PlasmaComponents.Label { |
||||
text: description |
||||
anchors.left: parent.left |
||||
anchors.right: parent.right |
||||
wrapMode: Text.Wrap |
||||
} |
||||
} |
||||
Grid { |
||||
anchors.top: tooltipIconWidget.bottom |
||||
anchors.topMargin: 16 |
||||
anchors.bottom: uninstallButton.top |
||||
anchors.bottomMargin: 4 |
||||
rows: 3 |
||||
columns: 2 |
||||
spacing: 4 |
||||
PlasmaComponents.Label { |
||||
text: i18n("License:") |
||||
} |
||||
PlasmaComponents.Label { |
||||
id: licenseText |
||||
text: license |
||||
wrapMode: Text.Wrap |
||||
} |
||||
PlasmaComponents.Label { |
||||
text: i18n("Author:") |
||||
} |
||||
PlasmaComponents.Label { |
||||
text: author |
||||
wrapMode: Text.Wrap |
||||
} |
||||
PlasmaComponents.Label { |
||||
text: i18n("Email:") |
||||
} |
||||
PlasmaComponents.Label { |
||||
text: email |
||||
} |
||||
} |
||||
|
||||
PlasmaComponents.Button { |
||||
id: uninstallButton |
||||
anchors { |
||||
horizontalCenter: parent.horizontalCenter |
||||
bottom: parent.bottom |
||||
} |
||||
opacity: local ? 1 : 0 |
||||
Behavior on opacity { |
||||
NumberAnimation { duration: 250 } |
||||
} |
||||
iconSource: "application-exit" |
||||
text: i18n("Uninstall") |
||||
onClicked: { |
||||
widgetExplorer.uninstall(pluginName) |
||||
tooltipDialog.visible = false |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,378 @@ |
||||
/* |
||||
* Copyright 2011 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU Library General Public License as |
||||
* published by the Free Software Foundation; either version 2 or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details |
||||
* |
||||
* You should have received a copy of the GNU Library General Public |
||||
* License along with this program; if not, write to the |
||||
* Free Software Foundation, Inc., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
import org.kde.plasma.components 2.0 as PlasmaComponents |
||||
import org.kde.plasma.core 2.0 as PlasmaCore |
||||
import org.kde.qtextracomponents 2.0 |
||||
|
||||
Item { |
||||
id: main |
||||
|
||||
width: 240 |
||||
height: 800 |
||||
//this is used to perfectly align the filter field and delegates |
||||
property int cellWidth: theme.defaultFont.pixelSize * 20 |
||||
|
||||
PlasmaCore.FrameSvgItem { |
||||
imagePath: "dialogs/background" |
||||
anchors.fill: parent |
||||
anchors.margins: margins |
||||
//color: "orange" |
||||
//opacity: 0.3 |
||||
} |
||||
|
||||
property int minimumWidth: cellWidth + ( |
||||
widgetExplorer.orientation == Qt.Horizontal |
||||
? 0 |
||||
: (scrollBar.width + 4 * 2) // 4 * 2 == left and right margins |
||||
) |
||||
property int minimumHeight: topBar.height + list.delegateHeight + (widgetExplorer.orientation == Qt.Horizontal ? scrollBar.height : 0) + 4 |
||||
|
||||
property Item getWidgetsButton |
||||
property Item categoryButton |
||||
|
||||
function i18n(inp) { return inp; } |
||||
|
||||
PlasmaComponents.ContextMenu { |
||||
id: categoriesDialog |
||||
visualParent: main.categoryButton |
||||
} |
||||
Repeater { |
||||
parent: categoriesDialog |
||||
model: widgetExplorer.filterModel |
||||
delegate: PlasmaComponents.MenuItem { |
||||
text: display |
||||
separator: model["separator"] != undefined ? model["separator"] : false |
||||
onClicked: { |
||||
list.contentX = 0 |
||||
list.contentY = 0 |
||||
main.categoryButton.text = display |
||||
widgetExplorer.widgetsModel.filterQuery = model["filterData"] |
||||
widgetExplorer.widgetsModel.filterType = model["filterType"] |
||||
} |
||||
Component.onCompleted: { |
||||
parent = categoriesDialog |
||||
} |
||||
} |
||||
} |
||||
|
||||
PlasmaComponents.ContextMenu { |
||||
id: getWidgetsDialog |
||||
visualParent: main.getWidgetsButton |
||||
} |
||||
Repeater { |
||||
parent: getWidgetsDialog |
||||
model: widgetExplorer.widgetsMenuActions |
||||
delegate: PlasmaComponents.MenuItem { |
||||
icon: modelData.icon |
||||
text: modelData.text |
||||
separator: modelData.separator |
||||
onClicked: modelData.trigger() |
||||
Component.onCompleted: { |
||||
parent = getWidgetsDialog |
||||
} |
||||
} |
||||
} |
||||
|
||||
PlasmaCore.Dialog { |
||||
id: tooltipDialog |
||||
property Item appletDelegate |
||||
|
||||
Component.onCompleted: { |
||||
tooltipDialog.setAttribute(Qt.WA_X11NetWmWindowTypeToolTip, true) |
||||
tooltipDialog.windowFlags = Qt.Window|Qt.WindowStaysOnTopHint|Qt.X11BypassWindowManagerHint |
||||
} |
||||
|
||||
onAppletDelegateChanged: { |
||||
if (!appletDelegate) { |
||||
toolTipHideTimer.restart() |
||||
toolTipShowTimer.running = false |
||||
} else if (tooltipDialog.visible) { |
||||
var point = main.tooltipPosition() |
||||
tooltipDialog.x = point.x |
||||
tooltipDialog.y = point.y |
||||
} else { |
||||
toolTipShowTimer.restart() |
||||
toolTipHideTimer.running = false |
||||
} |
||||
} |
||||
mainItem: Tooltip { id: tooltipWidget } |
||||
Behavior on x { |
||||
enabled: widgetExplorer.orientation == Qt.Horizontal |
||||
NumberAnimation { duration: 250 } |
||||
} |
||||
Behavior on y { |
||||
enabled: widgetExplorer.orientation == Qt.Vertical |
||||
NumberAnimation { duration: 250 } |
||||
} |
||||
} |
||||
Timer { |
||||
id: toolTipShowTimer |
||||
interval: 500 |
||||
repeat: false |
||||
onTriggered: { |
||||
var point = main.tooltipPosition() |
||||
tooltipDialog.x = point.x |
||||
tooltipDialog.y = point.y |
||||
tooltipDialog.visible = true |
||||
} |
||||
} |
||||
Timer { |
||||
id: toolTipHideTimer |
||||
interval: 1000 |
||||
repeat: false |
||||
onTriggered: tooltipDialog.visible = false |
||||
} |
||||
function tooltipPosition() { |
||||
return widgetExplorer.tooltipPosition(tooltipDialog.appletDelegate, tooltipDialog.width, tooltipDialog.height); |
||||
} |
||||
|
||||
Loader { |
||||
id: topBar |
||||
property Item categoryButton |
||||
|
||||
sourceComponent: (widgetExplorer.orientation == Qt.Horizontal) ? horizontalTopBarComponent : verticalTopBarComponent |
||||
height: item.height + 2 |
||||
anchors { |
||||
top: parent.top |
||||
left: parent.left |
||||
right: parent.right |
||||
|
||||
topMargin: widgetExplorer.orientation == Qt.Horizontal ? 4 : 0 |
||||
leftMargin: 4 |
||||
} |
||||
} |
||||
|
||||
Component { |
||||
id: horizontalTopBarComponent |
||||
|
||||
Item { |
||||
anchors { |
||||
top: parent.top |
||||
left: parent.left |
||||
right: parent.right |
||||
} |
||||
height: filterField.height |
||||
Row { |
||||
spacing: 5 |
||||
anchors { |
||||
left: parent.left |
||||
leftMargin: 2 |
||||
} |
||||
PlasmaComponents.TextField { |
||||
id: filterField |
||||
width: list.width / Math.floor(list.width / cellWidth) - 4 |
||||
clearButtonShown: true |
||||
placeholderText: i18n("Enter search term...") |
||||
onTextChanged: { |
||||
list.contentX = 0 |
||||
list.contentY = 0 |
||||
widgetExplorer.widgetsModel.searchTerm = text |
||||
} |
||||
Component.onCompleted: forceActiveFocus() |
||||
} |
||||
PlasmaComponents.Button { |
||||
id: categoryButton |
||||
text: i18n("Categories") |
||||
onClicked: categoriesDialog.open(0, categoryButton.height) |
||||
} |
||||
} |
||||
Row { |
||||
anchors.right: parent.right |
||||
spacing: 5 |
||||
PlasmaComponents.Button { |
||||
id: getWidgetsButton |
||||
iconSource: "get-hot-new-stuff" |
||||
text: i18n("Get new widgets") |
||||
onClicked: getWidgetsDialog.open() |
||||
} |
||||
|
||||
Repeater { |
||||
model: widgetExplorer.extraActions.length |
||||
PlasmaComponents.Button { |
||||
iconSource: widgetExplorer.extraActions[modelData].icon |
||||
text: widgetExplorer.extraActions[modelData].text |
||||
onClicked: { |
||||
widgetExplorer.extraActions[modelData].trigger() |
||||
} |
||||
} |
||||
} |
||||
PlasmaComponents.ToolButton { |
||||
iconSource: "window-close" |
||||
onClicked: widgetExplorer.closeClicked() |
||||
} |
||||
} |
||||
Component.onCompleted: { |
||||
main.getWidgetsButton = getWidgetsButton |
||||
main.categoryButton = categoryButton |
||||
} |
||||
} |
||||
} |
||||
|
||||
Component { |
||||
id: verticalTopBarComponent |
||||
|
||||
Column { |
||||
anchors.top: parent.top |
||||
anchors.left:parent.left |
||||
anchors.right: parent.right |
||||
spacing: 4 |
||||
|
||||
PlasmaComponents.ToolButton { |
||||
anchors.right: parent.right |
||||
iconSource: "window-close" |
||||
onClicked: widgetExplorer.closeClicked() |
||||
} |
||||
PlasmaComponents.TextField { |
||||
anchors { |
||||
left: parent.left |
||||
right: parent.right |
||||
} |
||||
clearButtonShown: true |
||||
placeholderText: i18n("Enter search term...") |
||||
onTextChanged: { |
||||
list.contentX = 0 |
||||
list.contentY = 0 |
||||
widgetExplorer.widgetsModel.searchTerm = text |
||||
} |
||||
Component.onCompleted: forceActiveFocus() |
||||
} |
||||
PlasmaComponents.Button { |
||||
anchors { |
||||
left: parent.left |
||||
right: parent.right |
||||
} |
||||
id: categoryButton |
||||
text: i18n("Categories") |
||||
onClicked: categoriesDialog.open(0, categoryButton.height) |
||||
} |
||||
Component.onCompleted: { |
||||
main.categoryButton = categoryButton |
||||
} |
||||
} |
||||
} |
||||
|
||||
MouseEventListener { |
||||
id: listParent |
||||
anchors { |
||||
top: topBar.bottom |
||||
left: parent.left |
||||
right: widgetExplorer.orientation == Qt.Horizontal |
||||
? parent.right |
||||
: (scrollBar.visible ? scrollBar.left : parent.right) |
||||
bottom: widgetExplorer.orientation == Qt.Horizontal ? scrollBar.top : bottomBar.top |
||||
leftMargin: 4 |
||||
bottomMargin: 4 |
||||
} |
||||
onWheelMoved: { |
||||
//use this only if the wheel orientation is vertical and the list orientation is horizontal, otherwise will be the list itself managing the wheel |
||||
if (wheel.orientation == Qt.Vertical && list.orientation == ListView.Horizontal) { |
||||
var delta = wheel.delta > 0 ? 20 : -20 |
||||
list.contentX = Math.min(Math.max(0, list.contentWidth - list.width), |
||||
Math.max(0, list.contentX - delta)) |
||||
} |
||||
} |
||||
ListView { |
||||
id: list |
||||
|
||||
property int delegateWidth: (widgetExplorer.orientation == Qt.Horizontal) ? (list.width / Math.floor(list.width / cellWidth)) : list.width |
||||
property int delegateHeight: theme.defaultFont.pixelSize * 7 - 4 |
||||
|
||||
anchors.fill: parent |
||||
|
||||
orientation: widgetExplorer.orientation == Qt.Horizontal ? ListView.Horizontal : ListView.Vertical |
||||
snapMode: ListView.SnapToItem |
||||
model: widgetExplorer.widgetsModel |
||||
|
||||
clip: widgetExplorer.orientation == Qt.Vertical |
||||
|
||||
delegate: AppletDelegate {} |
||||
} |
||||
|
||||
} |
||||
PlasmaComponents.ScrollBar { |
||||
id: scrollBar |
||||
orientation: widgetExplorer.orientation == Qt.Horizontal ? ListView.Horizontal : ListView.Vertical |
||||
anchors { |
||||
top: widgetExplorer.orientation == Qt.Horizontal ? undefined : listParent.top |
||||
bottom: widgetExplorer.orientation == Qt.Horizontal ? parent.bottom : bottomBar.top |
||||
left: widgetExplorer.orientation == Qt.Horizontal ? parent.left : undefined |
||||
right: parent.right |
||||
} |
||||
flickableItem: list |
||||
} |
||||
|
||||
Loader { |
||||
id: bottomBar |
||||
|
||||
sourceComponent: (widgetExplorer.orientation == Qt.Horizontal) ? undefined : verticalBottomBarComponent |
||||
//height: item.height |
||||
height: 48 // FIXME |
||||
anchors { |
||||
left: parent.left |
||||
right: parent.right |
||||
bottom: parent.bottom |
||||
leftMargin: 4 |
||||
} |
||||
} |
||||
|
||||
Component { |
||||
id: verticalBottomBarComponent |
||||
Column { |
||||
anchors { |
||||
left: parent.left |
||||
right: parent.right |
||||
bottom: parent.bottom |
||||
} |
||||
|
||||
spacing: 4 |
||||
|
||||
PlasmaComponents.Button { |
||||
anchors { |
||||
left: parent.left |
||||
right: parent.right |
||||
} |
||||
id: getWidgetsButton |
||||
iconSource: "get-hot-new-stuff" |
||||
text: i18n("Get new widgets") |
||||
onClicked: getWidgetsDialog.open() |
||||
} |
||||
|
||||
Repeater { |
||||
model: widgetExplorer.extraActions.length |
||||
PlasmaComponents.Button { |
||||
anchors { |
||||
left: parent.left |
||||
right: parent.right |
||||
} |
||||
iconSource: widgetExplorer.extraActions[modelData].icon |
||||
text: widgetExplorer.extraActions[modelData].text |
||||
onClicked: { |
||||
widgetExplorer.extraActions[modelData].trigger() |
||||
} |
||||
} |
||||
} |
||||
|
||||
Component.onCompleted: { |
||||
main.getWidgetsButton = getWidgetsButton |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,16 @@ |
||||
|
||||
// var panel = new Panel
|
||||
// panel.screen = 0
|
||||
// panel.location = 'top'
|
||||
// panel.addWidget("org.kde.testapplet")
|
||||
// panel.addWidget("org.kde.testcomponentsapplet")
|
||||
//
|
||||
// for (var i = 0; i < screenCount; ++i) {
|
||||
// var desktop = new Activity
|
||||
// desktop.name = i18n("Desktop")
|
||||
// desktop.screen = i
|
||||
// desktop.wallpaperPlugin = 'org.kde.image'
|
||||
//
|
||||
// desktop.addWidget("org.kde.testapplet")
|
||||
// var testComponents = desktop.addWidget("org.kde.testcomponentsapplet")
|
||||
// }
|
||||
@ -0,0 +1,67 @@ |
||||
/* vim:set foldmethod=marker: |
||||
* |
||||
* Copyright (C) 2013 Ivan Cukic <ivan.cukic(at)kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2, |
||||
* or (at your option) any later version, as published by the Free |
||||
* Software Foundation |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details |
||||
* |
||||
* You should have received a copy of the GNU General Public |
||||
* License along with this program; if not, write to the |
||||
* Free Software Foundation, Inc., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2 |
||||
import org.kde.plasma.hardware 0.1 as Hardware |
||||
import org.kde.plasma.platformcomponents 1.0 as Platform |
||||
import QtQuick.Window 2.0 |
||||
|
||||
Item { |
||||
id: main |
||||
|
||||
property string shell : "org.kde.blank" |
||||
property bool willing : hardware.touchscreenPresent |
||||
property int priority : 0 |
||||
|
||||
// This is not needed, but allows the |
||||
// handler to know whether its shell is loaded |
||||
property bool loaded : false |
||||
|
||||
Hardware.Interface { id: hardware } |
||||
|
||||
Platform.Application { |
||||
application: "xterm" |
||||
running: main.loaded |
||||
} |
||||
|
||||
// TODO: This is not needed - just for testing purposes |
||||
Window { |
||||
id: blankDialog |
||||
|
||||
visible: main.loaded |
||||
|
||||
width: 500 |
||||
height: 500 |
||||
|
||||
Rectangle { |
||||
anchors.fill: parent |
||||
color: "white" |
||||
} |
||||
|
||||
Text { |
||||
anchors.fill: parent |
||||
font.pointSize: 32 |
||||
text: "Blank" |
||||
horizontalAlignment: Text.AlignHCenter |
||||
verticalAlignment: Text.AlignVCenter |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,43 @@ |
||||
/* |
||||
* Copyright 2012 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
//import org.kde.plasma 2.0 |
||||
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore |
||||
|
||||
|
||||
Rectangle { |
||||
id: root |
||||
color: "gray" |
||||
width: 1024 |
||||
height: 768 |
||||
|
||||
property Item containment |
||||
|
||||
onContainmentChanged: { |
||||
print("New Containment: " + containment) |
||||
//containment.parent = root |
||||
containment.visible = true |
||||
containment.anchors.fill = root |
||||
} |
||||
|
||||
Component.onCompleted: { |
||||
print("View QML loaded") |
||||
} |
||||
} |
||||
@ -0,0 +1,43 @@ |
||||
/* |
||||
* Copyright 2012 Marco Martin <mart@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. |
||||
*/ |
||||
|
||||
import QtQuick 2.0 |
||||
//import org.kde.plasma 2.0 |
||||
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore |
||||
|
||||
|
||||
PlasmaCore.FrameSvgItem { |
||||
id: root |
||||
width: 640 |
||||
height: 32 |
||||
imagePath: "widgets/panel-background" |
||||
|
||||
property Item containment |
||||
|
||||
onContainmentChanged: { |
||||
print("New panel Containment: " + containment) |
||||
//containment.parent = root |
||||
containment.visible = true |
||||
containment.anchors.fill = root |
||||
} |
||||
|
||||
Component.onCompleted: { |
||||
print("PanelView QML loaded") |
||||
} |
||||
} |
||||
@ -0,0 +1,17 @@ |
||||
[Desktop Entry] |
||||
Comment=Blank desktop view furniture |
||||
Encoding=UTF-8 |
||||
Keywords= |
||||
Name=Blank Desktop |
||||
Type=Service |
||||
|
||||
X-KDE-ServiceTypes=Plasma/Shell |
||||
X-KDE-ParentApp= |
||||
X-KDE-PluginInfo-Author=Marco Martin |
||||
X-KDE-PluginInfo-Category= |
||||
X-KDE-PluginInfo-Email=mart@kde.org |
||||
X-KDE-PluginInfo-License=GPLv2+ |
||||
X-KDE-PluginInfo-Name=org.kde.blank |
||||
X-KDE-PluginInfo-Version= |
||||
X-KDE-PluginInfo-Website= |
||||
X-Plasma-MainScript=layout.js |
||||
@ -0,0 +1,420 @@ |
||||
/*
|
||||
* Copyright 2008 Aaron Seigo <aseigo@kde.org> |
||||
* Copyright 2013 Sebastian Kügler <sebas@kde.org> |
||||
* Copyright 2013 Ivan Cukic <ivan.cukic@kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU Library General Public License as |
||||
* published by the Free Software Foundation; either version 2, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details |
||||
* |
||||
* You should have received a copy of the GNU Library General Public |
||||
* License along with this program; if not, write to the |
||||
* Free Software Foundation, Inc., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
*/ |
||||
|
||||
#include "shellcorona.h" |
||||
|
||||
#include <QApplication> |
||||
#include <QDebug> |
||||
#include <QDesktopWidget> |
||||
#include <QQmlContext> |
||||
#include <QTimer> |
||||
|
||||
#include <KLocalizedString> |
||||
#include <Plasma/Package> |
||||
|
||||
#include "containmentconfigview.h" |
||||
#include "panelview.h" |
||||
#include "view.h" |
||||
#include "scripting/desktopscriptengine.h" |
||||
#include "widgetexplorer/widgetexplorerview.h" |
||||
#include "configview.h" |
||||
|
||||
class ShellCorona::Private { |
||||
public: |
||||
Private() |
||||
: desktopWidget(QApplication::desktop()), |
||||
widgetExplorerView(nullptr) |
||||
{ |
||||
appConfigSyncTimer.setSingleShot(true); |
||||
// constant controlling how long between requesting a configuration sync
|
||||
// and one happening should occur. currently 10 seconds
|
||||
appConfigSyncTimer.setInterval(10000); |
||||
} |
||||
|
||||
QString shell; |
||||
QDesktopWidget * desktopWidget; |
||||
QList <View *> views; |
||||
WidgetExplorerView * widgetExplorerView; |
||||
QHash <Plasma::Containment *, PanelView *> panelViews; |
||||
KConfigGroup desktopDefaultsConfig; |
||||
WorkspaceScripting::DesktopScriptEngine * scriptEngine; |
||||
QList<Plasma::Containment *> waitingPanels; |
||||
QSet<Plasma::Containment *> loadingDesktops; |
||||
|
||||
QTimer appConfigSyncTimer; |
||||
}; |
||||
|
||||
WorkspaceScripting::DesktopScriptEngine * ShellCorona::scriptEngine() const |
||||
{ |
||||
return d->scriptEngine; |
||||
} |
||||
|
||||
|
||||
ShellCorona::ShellCorona(QObject *parent) |
||||
: Plasma::Corona(parent), d(new Private()) |
||||
{ |
||||
d->desktopDefaultsConfig = KConfigGroup(KSharedConfig::openConfig(package().filePath("defaults")), "Desktop"); |
||||
|
||||
connect(&d->appConfigSyncTimer, &QTimer::timeout, |
||||
this, &ShellCorona::syncAppConfig); |
||||
|
||||
connect(d->desktopWidget, &QDesktopWidget::resized, |
||||
this, &ShellCorona::screenResized ); |
||||
connect(d->desktopWidget, &QDesktopWidget::screenCountChanged, |
||||
this, &ShellCorona::screenCountChanged); |
||||
connect(d->desktopWidget, &QDesktopWidget::workAreaResized, |
||||
this, &ShellCorona::workAreaResized); |
||||
|
||||
connect(this, &ShellCorona::containmentAdded, |
||||
this, &ShellCorona::handleContainmentAdded); |
||||
connect(this, &ShellCorona::screenOwnerChanged, |
||||
this, &ShellCorona::updateScreenOwner); |
||||
|
||||
d->scriptEngine = new WorkspaceScripting::DesktopScriptEngine(this, true); |
||||
|
||||
connect(d->scriptEngine, &WorkspaceScripting::ScriptEngine::printError, |
||||
this, &ShellCorona::printScriptError); |
||||
connect(d->scriptEngine, &WorkspaceScripting::ScriptEngine::print, |
||||
this, &ShellCorona::printScriptMessage); |
||||
|
||||
checkViews(); |
||||
|
||||
//QTimer::singleShot(600, this, SLOT(showWidgetExplorer())); // just for easier debugging
|
||||
} |
||||
|
||||
ShellCorona::~ShellCorona() |
||||
{ |
||||
} |
||||
|
||||
void ShellCorona::setShell(const QString & shell) |
||||
{ |
||||
if (d->shell == shell) return; |
||||
|
||||
unload(); |
||||
|
||||
setPackage(shell); |
||||
d->shell = shell; |
||||
|
||||
load(); |
||||
} |
||||
|
||||
QString ShellCorona::shell() const |
||||
{ |
||||
return d->shell; |
||||
} |
||||
|
||||
void ShellCorona::load() |
||||
{ |
||||
if (d->shell.isEmpty()) return; |
||||
|
||||
loadLayout(d->shell); |
||||
|
||||
if (containments().isEmpty()) { |
||||
loadDefaultLayout(); |
||||
} |
||||
|
||||
processUpdateScripts(); |
||||
checkScreens(); |
||||
} |
||||
|
||||
void ShellCorona::unload() |
||||
{ |
||||
if (d->shell.isEmpty()) return; |
||||
|
||||
qDeleteAll(containments()); |
||||
} |
||||
|
||||
KSharedConfig::Ptr ShellCorona::applicationConfig() |
||||
{ |
||||
return KSharedConfig::openConfig(); |
||||
} |
||||
|
||||
void ShellCorona::requestApplicationConfigSync() |
||||
{ |
||||
d->appConfigSyncTimer.start(); |
||||
} |
||||
|
||||
void ShellCorona::loadDefaultLayout() |
||||
{ |
||||
QString script = package().filePath("defaultlayout"); |
||||
qDebug() << "This is the default layout we are using:"; |
||||
|
||||
QFile file(script); |
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text) ) { |
||||
QString code = file.readAll(); |
||||
qDebug() << "evaluating startup script:" << script; |
||||
d->scriptEngine->evaluateScript(code); |
||||
} |
||||
} |
||||
|
||||
void ShellCorona::processUpdateScripts() |
||||
{ |
||||
foreach (const QString &script, WorkspaceScripting::ScriptEngine::pendingUpdateScripts(this)) { |
||||
d->scriptEngine->evaluateScript(script); |
||||
} |
||||
} |
||||
|
||||
void ShellCorona::checkScreens(bool signalWhenExists) |
||||
{ |
||||
// quick sanity check to ensure we have containments for each screen
|
||||
int num = numScreens(); |
||||
for (int i = 0; i < num; ++i) { |
||||
checkScreen(i, signalWhenExists); |
||||
} |
||||
} |
||||
|
||||
void ShellCorona::checkScreen(int screen, bool signalWhenExists) |
||||
{ |
||||
// signalWhenExists is there to allow PlasmaApp to know when to create views
|
||||
// it does this only on containment addition, but in the case of a screen being
|
||||
// added and the containment already existing for that screen, no signal is emitted
|
||||
// and so PlasmaApp does not know that it needs to create a view for it. to avoid
|
||||
// taking care of that case in PlasmaApp (which would duplicate some of the code below,
|
||||
// ShellCorona will, when signalWhenExists is true, emit a containmentAdded signal
|
||||
// even if the containment actually existed prior to this method being called.
|
||||
//
|
||||
//note: hte signal actually triggers view creation only for panels, atm.
|
||||
//desktop views are created in response to containment's screenChanged signal instead, which is
|
||||
//buggy (sometimes the containment thinks it's already on the screen, so no view is created)
|
||||
|
||||
//TODO: restore activities
|
||||
//Activity *currentActivity = activity(d->activityController->currentActivity());
|
||||
//ensure the desktop(s) have a containment and view
|
||||
checkDesktop(/*currentActivity,*/ signalWhenExists, screen); |
||||
|
||||
|
||||
//ensure the panels get views too
|
||||
if (signalWhenExists) { |
||||
foreach (Plasma::Containment * c, containments()) { |
||||
if (c->screen() != screen) { |
||||
continue; |
||||
} |
||||
|
||||
Plasma::Types::ContainmentType t = c->containmentType(); |
||||
if (t == Plasma::Types::PanelContainment || |
||||
t == Plasma::Types::CustomPanelContainment) { |
||||
emit containmentAdded(c); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
void ShellCorona::checkDesktop(/*Activity *activity,*/ bool signalWhenExists, int screen) |
||||
{ |
||||
Plasma::Containment *c = /*activity->*/containmentForScreen(screen); |
||||
|
||||
//TODO: remove following when activities are restored
|
||||
if (!c) { |
||||
c = createContainment(d->desktopDefaultsConfig.readEntry("Containment", "org.kde.desktopcontainment")); |
||||
} |
||||
|
||||
if (!c) { |
||||
return; |
||||
} |
||||
|
||||
c->setScreen(screen); |
||||
if (screen >= 0 || d->views.count() >= screen + 1) { |
||||
d->views[screen]->setContainment(c); |
||||
} else { |
||||
qWarning() << "Invalid screen"; |
||||
} |
||||
c->flushPendingConstraintsEvents(); |
||||
requestApplicationConfigSync(); |
||||
|
||||
if (signalWhenExists) { |
||||
emit containmentAdded(c); |
||||
} |
||||
} |
||||
|
||||
int ShellCorona::numScreens() const |
||||
{ |
||||
return d->desktopWidget->screenCount(); |
||||
} |
||||
|
||||
QRect ShellCorona::screenGeometry(int id) const |
||||
{ |
||||
return d->desktopWidget->screenGeometry(id); |
||||
} |
||||
|
||||
QRegion ShellCorona::availableScreenRegion(int id) const |
||||
{ |
||||
return d->desktopWidget->availableGeometry(id); |
||||
} |
||||
|
||||
QRect ShellCorona::availableScreenRect(int id) const |
||||
{ |
||||
return d->desktopWidget->availableGeometry(id); |
||||
} |
||||
|
||||
PanelView *ShellCorona::panelView(Plasma::Containment *containment) const |
||||
{ |
||||
return d->panelViews.value(containment); |
||||
} |
||||
|
||||
|
||||
///// SLOTS
|
||||
|
||||
void ShellCorona::screenCountChanged(int newCount) |
||||
{ |
||||
qDebug() << "New screen count" << newCount; |
||||
checkViews(); |
||||
} |
||||
|
||||
void ShellCorona::screenResized(int screen) |
||||
{ |
||||
qDebug() << "Screen resized" << screen; |
||||
} |
||||
|
||||
void ShellCorona::workAreaResized(int screen) |
||||
{ |
||||
qDebug() << "Work area resized" << screen; |
||||
} |
||||
|
||||
void ShellCorona::checkViews() |
||||
{ |
||||
if (d->views.count() == d->desktopWidget->screenCount()) { |
||||
return; |
||||
} else if (d->views.count() < d->desktopWidget->screenCount()) { |
||||
for (int i = d->views.count(); i < d->desktopWidget->screenCount(); ++i) { |
||||
View *view = new View(this); |
||||
QSurfaceFormat format; |
||||
view->show(); |
||||
|
||||
d->views << view; |
||||
} |
||||
} else { |
||||
for (int i = d->desktopWidget->screenCount(); i < d->views.count(); ++i) { |
||||
View *view = d->views.last(); |
||||
view->deleteLater(); |
||||
d->views.pop_back(); |
||||
} |
||||
} |
||||
|
||||
//check every containment is in proper view
|
||||
for (int i = 0; i < d->desktopWidget->screenCount(); ++i) { |
||||
qDebug() << "TODO: Implement loading containments into the views"; |
||||
} |
||||
} |
||||
|
||||
void ShellCorona::checkLoadingDesktopsComplete() |
||||
{ |
||||
Plasma::Containment *c = qobject_cast<Plasma::Containment *>(sender()); |
||||
if (c) { |
||||
disconnect(c, &Plasma::Containment::uiReadyChanged, |
||||
this, &ShellCorona::checkLoadingDesktopsComplete); |
||||
d->loadingDesktops.remove(c); |
||||
} |
||||
|
||||
if (d->loadingDesktops.isEmpty()) { |
||||
foreach (Plasma::Containment *cont, d->waitingPanels) { |
||||
d->panelViews[cont] = new PanelView(this); |
||||
d->panelViews[cont]->setContainment(cont); |
||||
} |
||||
d->waitingPanels.clear(); |
||||
} |
||||
} |
||||
|
||||
void ShellCorona::updateScreenOwner(int wasScreen, int isScreen, Plasma::Containment *containment) |
||||
{ |
||||
qDebug() << "Was screen" << wasScreen << "Is screen" << isScreen <<"Containment" << containment << containment->title(); |
||||
|
||||
if (containment->formFactor() == Plasma::Types::Horizontal || |
||||
containment->formFactor() == Plasma::Types::Vertical) { |
||||
|
||||
if (isScreen >= 0) { |
||||
d->waitingPanels << containment; |
||||
} else { |
||||
if (d->panelViews.contains(containment)) { |
||||
d->panelViews[containment]->setContainment(0); |
||||
d->panelViews[containment]->deleteLater(); |
||||
d->panelViews.remove(containment); |
||||
} |
||||
} |
||||
checkLoadingDesktopsComplete(); |
||||
|
||||
//Desktop view
|
||||
} else { |
||||
|
||||
if (containment->isUiReady()) { |
||||
checkLoadingDesktopsComplete(); |
||||
} else { |
||||
d->loadingDesktops.insert(containment); |
||||
connect(containment, &Plasma::Containment::uiReadyChanged, |
||||
this, &ShellCorona::checkLoadingDesktopsComplete); |
||||
} |
||||
|
||||
if (isScreen < 0 || d->views.count() < isScreen + 1) { |
||||
qWarning() << "Invalid screen"; |
||||
return; |
||||
} |
||||
|
||||
d->views[isScreen]->setContainment(containment); |
||||
} |
||||
} |
||||
|
||||
void ShellCorona::handleContainmentAdded(Plasma::Containment* c) |
||||
{ |
||||
connect(c, &Plasma::Containment::showAddWidgetsInterface, |
||||
this, &ShellCorona::showWidgetExplorer); |
||||
} |
||||
|
||||
void ShellCorona::showWidgetExplorer() |
||||
{ |
||||
if (!d->widgetExplorerView) { |
||||
|
||||
QString expqml = package().filePath("widgetexplorer"); |
||||
qDebug() << "Script to load for WidgetExplorer: " << expqml; |
||||
d->widgetExplorerView = new WidgetExplorerView(expqml); |
||||
d->widgetExplorerView->init(); |
||||
} |
||||
Plasma::Containment *c = 0; |
||||
c = dynamic_cast<Plasma::Containment*>(sender()); |
||||
if (c) { |
||||
qDebug() << "Found containment."; |
||||
d->widgetExplorerView->setContainment(c); |
||||
} else { |
||||
// FIXME: try harder to find a suitable containment?
|
||||
qWarning() << "containment not set, don't know where to add the applet."; |
||||
} |
||||
d->widgetExplorerView->show(); |
||||
} |
||||
|
||||
void ShellCorona::syncAppConfig() |
||||
{ |
||||
qDebug() << "Syncing plasma-shellrc config"; |
||||
applicationConfig()->sync(); |
||||
} |
||||
|
||||
void ShellCorona::printScriptError(const QString &error) |
||||
{ |
||||
qWarning() << error; |
||||
} |
||||
|
||||
void ShellCorona::printScriptMessage(const QString &message) |
||||
{ |
||||
qDebug() << message; |
||||
} |
||||
|
||||
// Desktop corona handler
|
||||
|
||||
|
||||
#include "moc_shellcorona.cpp" |
||||
|
||||
@ -0,0 +1,205 @@ |
||||
/*
|
||||
* Copyright (C) 2013 Ivan Cukic <ivan.cukic(at)kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2, |
||||
* or (at your option) any later version, as published by the Free |
||||
* Software Foundation |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details |
||||
* |
||||
* You should have received a copy of the GNU General Public |
||||
* License along with this program; if not, write to the |
||||
* Free Software Foundation, Inc., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
*/ |
||||
|
||||
#include "shellmanager.h" |
||||
|
||||
#include <algorithm> |
||||
|
||||
#include <QDebug> |
||||
#include <QDir> |
||||
#include <QList> |
||||
#include <QTimer> |
||||
|
||||
#include <QQmlEngine> |
||||
#include <QQmlComponent> |
||||
|
||||
#include <config-prefix.h> |
||||
#include "shellcorona.h" |
||||
#include "shellpluginloader.h" |
||||
|
||||
static const QString s_shellsDir( |
||||
QString(CMAKE_INSTALL_PREFIX) + "/" + DATA_INSTALL_DIR + "/" + "plasma/shells/"); |
||||
static const QString s_shellLoaderPath = QString("/contents/loader.qml"); |
||||
|
||||
//
|
||||
// ShellManager
|
||||
//
|
||||
|
||||
class ShellManager::Private { |
||||
public: |
||||
Private() |
||||
: currentHandler(nullptr) |
||||
{ |
||||
shellUpdateDelay.setInterval(100); |
||||
shellUpdateDelay.setSingleShot(true); |
||||
} |
||||
|
||||
QList<QObject *> handlers; |
||||
QObject * currentHandler; |
||||
QTimer shellUpdateDelay; |
||||
ShellCorona * corona; |
||||
}; |
||||
|
||||
ShellManager::ShellManager() |
||||
: d(new Private()) |
||||
{ |
||||
ShellPluginLoader::init(); |
||||
|
||||
connect( |
||||
&d->shellUpdateDelay, &QTimer::timeout, |
||||
this, &ShellManager::updateShell |
||||
); |
||||
|
||||
d->corona = new ShellCorona(this); |
||||
|
||||
connect( |
||||
this, &ShellManager::shellChanged, |
||||
d->corona, &ShellCorona::setShell |
||||
); |
||||
|
||||
loadHandlers(); |
||||
} |
||||
|
||||
ShellManager::~ShellManager() |
||||
{ |
||||
// if (d->currentHandler)
|
||||
// d->currentHandler->unload();
|
||||
} |
||||
|
||||
void ShellManager::loadHandlers() |
||||
{ |
||||
// TODO: Use corona's qml engine when it switches from QScriptEngine
|
||||
static QQmlEngine * engine = new QQmlEngine(this); |
||||
|
||||
for (const auto & dir: QDir(s_shellsDir).entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { |
||||
const QString qmlFile = s_shellsDir + dir + s_shellLoaderPath; |
||||
// qDebug() << "Making a new instance of " << qmlFile;
|
||||
|
||||
QQmlComponent handlerComponent(engine, |
||||
QUrl::fromLocalFile(qmlFile) |
||||
); |
||||
auto handler = handlerComponent.create(); |
||||
|
||||
// Writing out the errors
|
||||
for (const auto & error: handlerComponent.errors()) { |
||||
qWarning() << "Error: " << error; |
||||
} |
||||
|
||||
if (handler) { |
||||
registerHandler(handler); |
||||
} |
||||
} |
||||
|
||||
updateShell(); |
||||
} |
||||
|
||||
void ShellManager::registerHandler(QObject * handler) |
||||
{ |
||||
// qDebug() << "We got the handler: " << handler->property("shell").toString();
|
||||
|
||||
connect( |
||||
handler, &QObject::destroyed, |
||||
this, &ShellManager::deregisterHandler |
||||
); |
||||
|
||||
connect( |
||||
handler, SIGNAL(willingChanged()), |
||||
this, SLOT(requestShellUpdate()) |
||||
); |
||||
|
||||
connect( |
||||
handler, SIGNAL(priorityChanged()), |
||||
this, SLOT(requestShellUpdate()) |
||||
); |
||||
|
||||
d->handlers.push_back(handler); |
||||
} |
||||
|
||||
void ShellManager::deregisterHandler(QObject * handler) |
||||
{ |
||||
if (d->handlers.contains(handler)) { |
||||
d->handlers.removeAll(handler); |
||||
|
||||
handler->disconnect(this); |
||||
} |
||||
|
||||
if (d->currentHandler == handler) |
||||
d->currentHandler = nullptr; |
||||
} |
||||
|
||||
void ShellManager::requestShellUpdate() |
||||
{ |
||||
d->shellUpdateDelay.start(); |
||||
} |
||||
|
||||
void ShellManager::updateShell() |
||||
{ |
||||
d->shellUpdateDelay.stop(); |
||||
|
||||
if (d->handlers.isEmpty()) { |
||||
qFatal("We have no shell handlers installed"); |
||||
return; |
||||
} |
||||
|
||||
// Finding the handler that has the priority closest to zero.
|
||||
// We will return a handler even if there are no willing ones.
|
||||
|
||||
auto handler =* std::min_element(d->handlers.cbegin(), d->handlers.cend(), |
||||
[] (QObject * left, QObject * right) |
||||
{ |
||||
auto willing = [] (QObject * handler) |
||||
{ |
||||
return handler->property("willing").toBool(); |
||||
}; |
||||
|
||||
auto priority = [] (QObject * handler) |
||||
{ |
||||
return handler->property("priority").toInt(); |
||||
}; |
||||
|
||||
return |
||||
// If one is willing and the other is not,
|
||||
// return it - it has the priority
|
||||
willing(left) && !willing(right) ? true : |
||||
!willing(left) && willing(right) ? false : |
||||
// otherwise just compare the priorities
|
||||
priority(left) < priority(right); |
||||
} |
||||
); |
||||
|
||||
if (handler == d->currentHandler) return; |
||||
|
||||
// Activating the new handler and killing the old one
|
||||
if (d->currentHandler) { |
||||
d->currentHandler->setProperty("loaded", false); |
||||
} |
||||
|
||||
d->currentHandler = handler; |
||||
d->currentHandler->setProperty("loaded", true); |
||||
|
||||
// d->corona->setShell(d->currentHandler->property("shell").toString());
|
||||
emit shellChanged(d->currentHandler->property("shell").toString()); |
||||
} |
||||
|
||||
ShellManager * ShellManager::instance() |
||||
{ |
||||
static ShellManager manager; |
||||
return &manager; |
||||
} |
||||
|
||||
@ -0,0 +1,52 @@ |
||||
/*
|
||||
* Copyright (C) 2013 Ivan Cukic <ivan.cukic(at)kde.org> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2, |
||||
* or (at your option) any later version, as published by the Free |
||||
* Software Foundation |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details |
||||
* |
||||
* You should have received a copy of the GNU General Public |
||||
* License along with this program; if not, write to the |
||||
* Free Software Foundation, Inc., |
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
*/ |
||||
|
||||
#ifndef SHELLMANAGER_H |
||||
#define SHELLMANAGER_H |
||||
|
||||
#include <QObject> |
||||
|
||||
class ShellManager: public QObject { |
||||
Q_OBJECT |
||||
public: |
||||
static ShellManager * instance(); |
||||
~ShellManager(); |
||||
|
||||
void loadHandlers(); |
||||
|
||||
protected Q_SLOTS: |
||||
void registerHandler(QObject * handler); |
||||
void deregisterHandler(QObject * handler); |
||||
|
||||
public Q_SLOTS: |
||||
void requestShellUpdate(); |
||||
void updateShell(); |
||||
|
||||
Q_SIGNALS: |
||||
void shellChanged(const QString & shell); |
||||
|
||||
private: |
||||
ShellManager(); |
||||
|
||||
class Private; |
||||
const QScopedPointer<Private> d; |
||||
}; |
||||
|
||||
#endif /* SHELLMANAGER_H */ |
||||
|
||||
Loading…
Reference in new issue