mirror of
https://github.com/KDE/latte-dock.git
synced 2025-02-07 13:57:40 +03:00
eefbc5e9ec
--changed the design totally and use only signals between plasmoid in order to update their models. This way the launcherList from their tasksmodel should be updated only on the initialization phase of the Latte plasmoid. Afterwards signaling between them takes place, in order to inform each other for adding, removing launchers, moving them and assigning them to activities
441 lines
12 KiB
C++
441 lines
12 KiB
C++
/*
|
|
* Copyright 2017 Smith AR <audoban@openmailbox.org>
|
|
* Michail Vourlakos <mvourlakos@gmail.com>
|
|
*
|
|
* This file is part of Latte-Dock
|
|
*
|
|
* Latte-Dock 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.
|
|
*
|
|
* Latte-Dock 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "layoutmanager.h"
|
|
#include "infoview.h"
|
|
|
|
#include <QDir>
|
|
#include <QFile>
|
|
#include <QQmlProperty>
|
|
#include <QtDBus/QtDBus>
|
|
|
|
#include <KActivities/Consumer>
|
|
#include <KLocalizedString>
|
|
#include <KNotification>
|
|
|
|
namespace Latte {
|
|
|
|
LayoutManager::LayoutManager(QObject *parent)
|
|
: QObject(parent),
|
|
m_importer(new Importer(this)),
|
|
m_launchersSignals(new LaunchersSignals(this))
|
|
{
|
|
m_corona = qobject_cast<DockCorona *>(parent);
|
|
|
|
if (m_corona) {
|
|
//! create the add widgets action
|
|
const QIcon addWidIcon = QIcon::fromTheme("add");
|
|
m_addWidgetsAction = new QAction(addWidIcon, i18n("Add Widgets..."), this);
|
|
m_addWidgetsAction->setStatusTip(i18n("Show Plasma Widget Explorer"));
|
|
connect(m_addWidgetsAction, &QAction::triggered, this, &LayoutManager::showWidgetsExplorer);
|
|
|
|
connect(m_corona->universalSettings(), &UniversalSettings::currentLayoutNameChanged, this, &LayoutManager::currentLayoutNameChanged);
|
|
connect(m_corona->universalSettings(), &UniversalSettings::showInfoWindowChanged, this, &LayoutManager::showInfoWindowChanged);
|
|
|
|
m_dynamicSwitchTimer.setSingleShot(true);
|
|
showInfoWindowChanged();
|
|
connect(&m_dynamicSwitchTimer, &QTimer::timeout, this, &LayoutManager::confirmDynamicSwitch);
|
|
}
|
|
}
|
|
|
|
LayoutManager::~LayoutManager()
|
|
{
|
|
m_importer->deleteLater();
|
|
m_launchersSignals->deleteLater();
|
|
|
|
if (m_currentLayout) {
|
|
m_currentLayout->deleteLater();
|
|
}
|
|
}
|
|
|
|
void LayoutManager::load()
|
|
{
|
|
int configVer = m_corona->universalSettings()->version();
|
|
qDebug() << "Universal Settings version : " << configVer;
|
|
|
|
if (configVer < 2 && QFile(QDir::homePath() + "/.config/lattedockrc").exists()) {
|
|
qDebug() << "Latte must update its configuration...";
|
|
m_importer->updateOldConfiguration();
|
|
importPresets(false);
|
|
} else if (!QFile(QDir::homePath() + "/.config/lattedockrc").exists()) {
|
|
//startup create what is necessary....
|
|
QDir layoutDir(QDir::homePath() + "/.config/latte");
|
|
|
|
if (!layoutDir.exists()) {
|
|
QDir(QDir::homePath() + "/.config").mkdir("latte");
|
|
}
|
|
|
|
newLayout(i18n("My Layout"));
|
|
importPresets(false);
|
|
m_corona->universalSettings()->setCurrentLayoutName(i18n("My Layout"));
|
|
m_corona->universalSettings()->setVersion(2);
|
|
}
|
|
|
|
qDebug() << "Latte is loading its layouts...";
|
|
|
|
connect(m_corona->m_activityConsumer, &KActivities::Consumer::currentActivityChanged,
|
|
this, &LayoutManager::currentActivityChanged);
|
|
|
|
loadLayouts();
|
|
}
|
|
|
|
DockCorona *LayoutManager::corona()
|
|
{
|
|
return m_corona;
|
|
}
|
|
|
|
Importer *LayoutManager::importer()
|
|
{
|
|
return m_importer;
|
|
}
|
|
|
|
QAction *LayoutManager::addWidgetsAction()
|
|
{
|
|
return m_addWidgetsAction;
|
|
}
|
|
|
|
LayoutSettings *LayoutManager::currentLayout()
|
|
{
|
|
return m_currentLayout;
|
|
}
|
|
|
|
LaunchersSignals *LayoutManager::launchersSignals()
|
|
{
|
|
return m_launchersSignals;
|
|
}
|
|
|
|
QString LayoutManager::currentLayoutName() const
|
|
{
|
|
if (m_corona && m_corona->universalSettings()) {
|
|
return m_corona->universalSettings()->currentLayoutName();
|
|
}
|
|
|
|
return QString();
|
|
}
|
|
|
|
QStringList LayoutManager::layouts() const
|
|
{
|
|
return m_layouts;
|
|
}
|
|
|
|
QStringList LayoutManager::menuLayouts() const
|
|
{
|
|
QStringList fixedMenuLayouts = m_menuLayouts;
|
|
|
|
//! in case the current layout isnt checked to be shown in the menus
|
|
//! we must add it on top
|
|
if (!fixedMenuLayouts.contains(currentLayoutName())) {
|
|
fixedMenuLayouts.prepend(currentLayoutName());
|
|
}
|
|
|
|
return fixedMenuLayouts;
|
|
}
|
|
|
|
void LayoutManager::setMenuLayouts(QStringList layouts)
|
|
{
|
|
if (m_menuLayouts == layouts) {
|
|
return;
|
|
}
|
|
|
|
m_menuLayouts = layouts;
|
|
emit menuLayoutsChanged();
|
|
}
|
|
|
|
QStringList LayoutManager::activities()
|
|
{
|
|
return m_corona->m_activityConsumer->activities();
|
|
}
|
|
|
|
QStringList LayoutManager::presetsPaths() const
|
|
{
|
|
return m_presetsPaths;
|
|
}
|
|
|
|
QString LayoutManager::layoutPath(QString layoutName)
|
|
{
|
|
QString path = QDir::homePath() + "/.config/latte/" + layoutName + ".layout.latte";
|
|
|
|
if (!QFile(path).exists()) {
|
|
path = "";
|
|
}
|
|
|
|
return path;
|
|
}
|
|
|
|
void LayoutManager::currentActivityChanged(const QString &id)
|
|
{
|
|
qDebug() << "activity changed :: " << id;
|
|
|
|
m_shouldSwitchToLayout = shouldSwitchToLayout(id);
|
|
|
|
m_dynamicSwitchTimer.start();
|
|
}
|
|
|
|
void LayoutManager::showInfoWindowChanged()
|
|
{
|
|
if (m_corona->universalSettings()->showInfoWindow()) {
|
|
m_dynamicSwitchTimer.setInterval(1800);
|
|
} else {
|
|
m_dynamicSwitchTimer.setInterval(2300);
|
|
}
|
|
}
|
|
|
|
QString LayoutManager::shouldSwitchToLayout(QString activityId)
|
|
{
|
|
if (m_assignedLayouts.contains(activityId) && m_assignedLayouts[activityId] != currentLayoutName()) {
|
|
return m_assignedLayouts[activityId];
|
|
} else if (!m_assignedLayouts.contains(activityId) && !m_corona->universalSettings()->lastNonAssignedLayoutName().isEmpty()
|
|
&& m_corona->universalSettings()->lastNonAssignedLayoutName() != currentLayoutName()) {
|
|
return m_corona->universalSettings()->lastNonAssignedLayoutName();
|
|
}
|
|
|
|
return QString();
|
|
}
|
|
|
|
void LayoutManager::confirmDynamicSwitch()
|
|
{
|
|
QString tempShouldSwitch = shouldSwitchToLayout(m_corona->m_activityConsumer->currentActivity());
|
|
|
|
if (tempShouldSwitch.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
if (m_shouldSwitchToLayout == tempShouldSwitch && m_shouldSwitchToLayout != currentLayoutName()) {
|
|
qDebug() << "dynamic switch to layout :: " << m_shouldSwitchToLayout;
|
|
|
|
if (m_corona->universalSettings()->showInfoWindow()) {
|
|
showInfoWindow(i18n("Switching to layout <b>%0</b> ...").arg(m_shouldSwitchToLayout), 4000);
|
|
|
|
QTimer::singleShot(500, [this, tempShouldSwitch]() {
|
|
switchToLayout(tempShouldSwitch);
|
|
});
|
|
} else {
|
|
switchToLayout(m_shouldSwitchToLayout);
|
|
}
|
|
|
|
} else {
|
|
m_shouldSwitchToLayout = tempShouldSwitch;
|
|
m_dynamicSwitchTimer.start();
|
|
}
|
|
}
|
|
|
|
void LayoutManager::loadLayouts()
|
|
{
|
|
m_layouts.clear();
|
|
m_menuLayouts.clear();
|
|
m_presetsPaths.clear();
|
|
m_assignedLayouts.clear();
|
|
|
|
QDir layoutDir(QDir::homePath() + "/.config/latte");
|
|
QStringList filter;
|
|
filter.append(QString("*.layout.latte"));
|
|
QStringList files = layoutDir.entryList(filter, QDir::Files | QDir::NoSymLinks);
|
|
|
|
foreach (auto layout, files) {
|
|
LayoutSettings layoutSets(this, layoutDir.absolutePath() + "/" + layout);
|
|
|
|
QStringList validActivityIds = validActivities(layoutSets.activities());
|
|
layoutSets.setActivities(validActivityIds);
|
|
|
|
foreach (auto activity, validActivityIds) {
|
|
m_assignedLayouts[activity] = layoutSets.name();
|
|
}
|
|
|
|
m_layouts.append(layoutSets.name());
|
|
|
|
if (layoutSets.showInMenu()) {
|
|
m_menuLayouts.append(layoutSets.name());
|
|
}
|
|
}
|
|
|
|
m_presetsPaths.append(m_corona->kPackage().filePath("preset1"));
|
|
m_presetsPaths.append(m_corona->kPackage().filePath("preset2"));
|
|
m_presetsPaths.append(m_corona->kPackage().filePath("preset3"));
|
|
m_presetsPaths.append(m_corona->kPackage().filePath("preset4"));
|
|
|
|
emit layoutsChanged();
|
|
emit menuLayoutsChanged();
|
|
}
|
|
|
|
bool LayoutManager::switchToLayout(QString layoutName)
|
|
{
|
|
if (m_currentLayout && m_currentLayout->name() == layoutName) {
|
|
return false;
|
|
}
|
|
|
|
QString lPath = layoutPath(layoutName);
|
|
|
|
if (lPath.isEmpty() && layoutName == i18n("Alternative")) {
|
|
lPath = newLayout(i18n("Alternative"), i18n("Default"));
|
|
}
|
|
|
|
if (!lPath.isEmpty()) {
|
|
//! this code must be called asynchronously because it is called
|
|
//! also from qml (Tasks plasmoid). This change fixes a very important
|
|
//! crash when switching sessions through the Tasks plasmoid Context menu
|
|
//! Latte was unstable and was crashing very often during changing
|
|
//! sessions.
|
|
QTimer::singleShot(0, [this, layoutName, lPath]() {
|
|
qDebug() << layoutName << " - " << lPath;
|
|
|
|
m_corona->loadLatteLayout(lPath);
|
|
m_corona->universalSettings()->setCurrentLayoutName(layoutName);
|
|
|
|
if (!layoutIsAssigned(layoutName)) {
|
|
m_corona->universalSettings()->setLastNonAssignedLayoutName(layoutName);
|
|
}
|
|
|
|
if (m_currentLayout) {
|
|
m_currentLayout->deleteLater();
|
|
}
|
|
|
|
m_currentLayout = new LayoutSettings(this, lPath, layoutName);
|
|
|
|
emit currentLayoutChanged();
|
|
});
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
QString LayoutManager::newLayout(QString layoutName, QString preset)
|
|
{
|
|
QDir layoutDir(QDir::homePath() + "/.config/latte");
|
|
QStringList filter;
|
|
filter.append(QString(layoutName + "*.layout.latte"));
|
|
QStringList files = layoutDir.entryList(filter, QDir::Files | QDir::NoSymLinks);
|
|
|
|
//! if the newLayout already exists provide a newName that doesnt
|
|
if (files.count() >= 1) {
|
|
int newCounter = files.count() + 1;
|
|
|
|
layoutName = layoutName + "-" + QString::number(newCounter);
|
|
}
|
|
|
|
QString newLayoutPath = layoutDir.absolutePath() + "/" + layoutName + ".layout.latte";
|
|
|
|
qDebug() << "adding layout : " << layoutName << " based on preset:" << preset;
|
|
|
|
if (preset == i18n("Default") && !QFile(newLayoutPath).exists()) {
|
|
qDebug() << "adding layout : succeed";
|
|
QFile(m_corona->kPackage().filePath("preset1")).copy(newLayoutPath);
|
|
}
|
|
|
|
return newLayoutPath;
|
|
}
|
|
|
|
void LayoutManager::importPresets(bool includeDefault)
|
|
{
|
|
int start = 1;
|
|
|
|
if (!includeDefault) {
|
|
start = 2;
|
|
}
|
|
|
|
for (int i = start; i <= 4; ++i) {
|
|
QByteArray presetNameOrig = QString("preset" + QString::number(i)).toUtf8();
|
|
QString presetPath = m_corona->kPackage().filePath(presetNameOrig);
|
|
QString presetName = LayoutSettings::layoutName(presetPath);
|
|
QByteArray presetNameChars = presetName.toUtf8();
|
|
presetName = i18n(presetNameChars);
|
|
|
|
QString newLayoutFile = QDir::homePath() + "/.config/latte/" + presetName + ".layout.latte";
|
|
|
|
if (!QFile(newLayoutFile).exists()) {
|
|
QFile(presetPath).copy(newLayoutFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
QStringList LayoutManager::validActivities(QStringList currentList)
|
|
{
|
|
QStringList validIds;
|
|
|
|
foreach (auto activity, currentList) {
|
|
if (activities().contains(activity)) {
|
|
validIds.append(activity);
|
|
}
|
|
}
|
|
|
|
return validIds;
|
|
}
|
|
|
|
bool LayoutManager::layoutIsAssigned(QString layoutName)
|
|
{
|
|
QHashIterator<const QString, QString> i(m_assignedLayouts);
|
|
|
|
while (i.hasNext()) {
|
|
i.next();
|
|
|
|
if (i.value() == layoutName) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void LayoutManager::showLayoutConfigDialog()
|
|
{
|
|
if (!m_layoutConfigDialog)
|
|
m_layoutConfigDialog = new LayoutConfigDialog(nullptr, this);
|
|
|
|
m_layoutConfigDialog->show();
|
|
|
|
if (m_layoutConfigDialog->isMinimized()) {
|
|
m_layoutConfigDialog->showNormal();
|
|
}
|
|
|
|
m_layoutConfigDialog->activateWindow();
|
|
}
|
|
|
|
void LayoutManager::showInfoWindow(QString info, int duration)
|
|
{
|
|
foreach (auto screen, qGuiApp->screens()) {
|
|
InfoView *infoView = new InfoView(m_corona, info, screen);
|
|
|
|
infoView->show();
|
|
|
|
QTimer::singleShot(duration, [this, infoView]() {
|
|
infoView->deleteLater();
|
|
});
|
|
}
|
|
}
|
|
|
|
void LayoutManager::showWidgetsExplorer()
|
|
{
|
|
QDBusInterface iface("org.kde.plasmashell", "/PlasmaShell", "", QDBusConnection::sessionBus());
|
|
|
|
if (iface.isValid()) {
|
|
iface.call("toggleWidgetExplorer");
|
|
}
|
|
}
|
|
|
|
//! it is used just in order to provide translations for the presets
|
|
void LayoutManager::ghostForTranslatedPresets()
|
|
{
|
|
QString preset1 = i18n("Default");
|
|
QString preset2 = i18n("Plasma");
|
|
QString preset3 = i18n("Unity");
|
|
QString preset4 = i18n("Extended");
|
|
}
|
|
|
|
}
|