File indexing completed on 2024-04-14 05:46:47
0001 /* 0002 Copyright (C) 2005-2006 Tom Albers <toma@kde.org> 0003 Copyright (C) 2011 Aurélien Gâteau <agateau@kde.org> 0004 0005 Orginal copied from ksynaptics: 0006 Copyright (C) 2004 Nadeem Hasan <nhasan@kde.org> 0007 0008 This program is free software; you can redistribute it and/or 0009 modify it under the terms of the GNU General Public 0010 License as published by the Free Software Foundation; either 0011 version 2 of the License, or (at your option) any later version. 0012 0013 This program is distributed in the hope that it will be useful, 0014 but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0016 General Public License for more details. 0017 0018 You should have received a copy of the GNU General Public License 0019 along with this program; if not, write to the Free Software 0020 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 0021 */ 0022 0023 #include "rsidock.h" 0024 #include "rsistats.h" 0025 #include "rsistatwidget.h" 0026 #include "setup.h" 0027 0028 #include <QIcon> 0029 #include <QPointer> 0030 #include <QTextDocument> 0031 0032 #include <KAboutData> 0033 #include <KConfigGroup> 0034 #include <KHelpMenu> 0035 #include <KLocalizedString> 0036 #include <KMessageBox> 0037 #include <KNotifyConfigWidget> 0038 #include <KStandardShortcut> 0039 #include <KWindowSystem> 0040 #include <QDebug> 0041 #include <QDialogButtonBox> 0042 #include <QMenu> 0043 #include <QPushButton> 0044 #include <QVBoxLayout> 0045 0046 template<typename Func, typename Object> 0047 static QAction *doAddAction(QMenu *menu, const QString &text, Object *receiver, Func func) 0048 { 0049 QAction *action = menu->addAction(text); 0050 QObject::connect(action, &QAction::triggered, receiver, func); 0051 return action; 0052 } 0053 0054 template<typename Func, typename Object> 0055 static QAction *doAddAction(QMenu *menu, const QIcon &icon, const QString &text, Object *receiver, Func func) 0056 { 0057 QAction *action = doAddAction(menu, text, receiver, func); 0058 action->setIcon(icon); 0059 return action; 0060 } 0061 0062 RSIDock::RSIDock(QObject *parent) 0063 : KStatusNotifierItem(parent) 0064 , m_suspended(false) 0065 , m_statsDialog(nullptr) 0066 , m_statsWidget(nullptr) 0067 { 0068 setCategory(ApplicationStatus); 0069 setStatus(Active); 0070 0071 const KAboutData &aboutData = KAboutData::applicationData(); 0072 setTitle(aboutData.displayName()); 0073 setToolTipTitle(aboutData.displayName()); 0074 0075 m_help = new KHelpMenu(nullptr, aboutData); 0076 0077 QMenu *menu = contextMenu(); 0078 doAddAction(menu, QIcon::fromTheme("kde"), i18n("About &KDE"), m_help, &KHelpMenu::aboutKDE); 0079 doAddAction(menu, i18n("&About RSIBreak"), m_help, &KHelpMenu::aboutApplication); 0080 doAddAction(menu, QIcon::fromTheme("help-contents"), i18n("RSIBreak &Handbook"), m_help, &KHelpMenu::appHelpActivated); 0081 0082 menu->addSeparator(); 0083 doAddAction(menu, QIcon::fromTheme("tools-report-bug"), i18n("&Report Bug..."), m_help, &KHelpMenu::reportBug); 0084 doAddAction(menu, i18n("Switch application &language..."), m_help, &KHelpMenu::switchApplicationLanguage); 0085 0086 menu->addSeparator(); 0087 m_suspendItem = doAddAction(menu, QIcon::fromTheme("media-playback-pause"), i18n("&Suspend RSIBreak"), this, &RSIDock::slotToggleSuspend); 0088 doAddAction(menu, QIcon::fromTheme("view-statistics"), i18n("&Usage Statistics"), this, &RSIDock::slotShowStatistics); 0089 doAddAction(menu, QIcon::fromTheme("preferences-desktop-notification"), i18n("Configure &Notifications..."), this, &RSIDock::slotConfigureNotifications); 0090 doAddAction(menu, QIcon::fromTheme("configure"), i18n("&Configure RSIBreak..."), this, &RSIDock::slotConfigure); 0091 0092 connect(this, &RSIDock::activateRequested, this, &RSIDock::slotShowStatistics); 0093 } 0094 0095 RSIDock::~RSIDock() 0096 { 0097 delete m_help; 0098 delete m_statsWidget; 0099 delete m_statsDialog; 0100 m_statsWidget = nullptr; 0101 } 0102 0103 void RSIDock::doResume() 0104 { 0105 if (m_suspended) 0106 slotToggleSuspend(); 0107 } 0108 0109 void RSIDock::doSuspend() 0110 { 0111 if (!m_suspended) 0112 slotToggleSuspend(); 0113 } 0114 0115 void RSIDock::slotConfigureNotifications() 0116 { 0117 KNotifyConfigWidget::configure(nullptr); 0118 } 0119 0120 void RSIDock::slotConfigure() 0121 { 0122 // don't think it is needed, because setup is not accessed after the 0123 // exec call, but better safe than crash. 0124 QPointer<Setup> setup = new Setup(nullptr); 0125 emit dialogEntered(); 0126 if (setup->exec() == QDialog::Accepted) 0127 emit configChanged(); 0128 delete setup; 0129 0130 if (!m_suspended) 0131 emit dialogLeft(); 0132 } 0133 0134 void RSIDock::slotToggleSuspend() 0135 { 0136 if (m_suspended) { 0137 emit suspend(false); 0138 0139 setIconByName("rsibreak0"); 0140 m_suspendItem->setIcon(QIcon::fromTheme("media-playback-pause")); 0141 m_suspendItem->setText(i18n("&Suspend RSIBreak")); 0142 } else { 0143 emit suspend(true); 0144 0145 setIconByName("rsibreakx"); 0146 m_suspendItem->setIcon(QIcon::fromTheme("media-playback-start")); 0147 m_suspendItem->setText(i18n("&Resume RSIBreak")); 0148 } 0149 0150 m_suspended = !m_suspended; 0151 } 0152 0153 void RSIDock::slotShowStatistics() 0154 { 0155 if (!m_statsDialog) { 0156 m_statsDialog = new QDialog(nullptr); 0157 m_statsDialog->setWindowTitle(i18n("Usage Statistics")); 0158 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); 0159 QVBoxLayout *mainLayout = new QVBoxLayout; 0160 m_statsDialog->setLayout(mainLayout); 0161 QPushButton *user1Button = new QPushButton; 0162 buttonBox->addButton(user1Button, QDialogButtonBox::ActionRole); 0163 connect(buttonBox, &QDialogButtonBox::accepted, m_statsDialog, &QDialog::accept); 0164 connect(buttonBox, &QDialogButtonBox::rejected, m_statsDialog, &QDialog::reject); 0165 0166 user1Button->setText(i18n("Reset")); 0167 0168 m_statsWidget = new RSIStatWidget(m_statsDialog); 0169 connect(user1Button, &QPushButton::clicked, this, &RSIDock::slotResetStats); 0170 0171 mainLayout->addWidget(m_statsWidget); 0172 mainLayout->addWidget(buttonBox); 0173 } 0174 0175 if (m_statsDialog->isVisible() && KWindowInfo(m_statsDialog->winId(), NET::WMDesktop).isOnCurrentDesktop()) { 0176 m_statsDialog->hide(); 0177 } else { 0178 m_statsDialog->show(); 0179 0180 if (!m_statsDialog->isActiveWindow()) 0181 KWindowSystem::forceActiveWindow(m_statsDialog->winId()); 0182 0183 m_statsDialog->raise(); 0184 } 0185 } 0186 0187 void RSIDock::slotResetStats() 0188 { 0189 int i = KMessageBox::warningContinueCancel(nullptr, 0190 i18n("This will reset all statistics to zero. " 0191 "Is that what you want?"), 0192 i18n("Reset the statistics"), 0193 KGuiItem(i18n("Reset")), 0194 KStandardGuiItem::cancel(), 0195 "resetStatistics"); 0196 0197 if (i == KMessageBox::Continue) 0198 RSIGlobals::instance()->stats()->reset(); 0199 } 0200 0201 static QString colorizedText(const QString &text, const QColor &color) 0202 { 0203 return QString("<font color='%1'>●</font> %2").arg(color.name(), text.toHtmlEscaped()); 0204 } 0205 0206 void RSIDock::setCounters(int tiny_left, int big_left) 0207 { 0208 if (m_suspended) 0209 setToolTipSubTitle(i18n("Suspended")); 0210 else { 0211 bool tinyBreaks = RSIGlobals::instance()->useTinyBreaks(); 0212 0213 QColor tinyColor; 0214 if (tinyBreaks) { 0215 tinyColor = RSIGlobals::instance()->getTinyBreakColor(tiny_left); 0216 RSIGlobals::instance()->stats()->setColor(LAST_TINY_BREAK, tinyColor); 0217 } 0218 0219 QColor bigColor = RSIGlobals::instance()->getBigBreakColor(big_left); 0220 RSIGlobals::instance()->stats()->setColor(LAST_BIG_BREAK, bigColor); 0221 0222 // Only add the line for the tiny break when there is not 0223 // a big break planned at the same time. 0224 0225 QStringList lines; 0226 if (tinyBreaks && tiny_left != big_left) { 0227 QString formattedText = RSIGlobals::instance()->formatSeconds(tiny_left); 0228 if (!formattedText.isNull()) { 0229 lines << colorizedText(i18n("%1 remaining until next short break", formattedText), tinyColor); 0230 } 0231 } 0232 0233 // do the same for the big break 0234 if (big_left > 0) 0235 lines << colorizedText(i18n("%1 remaining until next long break", RSIGlobals::instance()->formatSeconds(big_left)), bigColor); 0236 setToolTipSubTitle(lines.join("<br />")); 0237 } 0238 }