1 /*
2   This file is part of KOrganizer.
3 
4   SPDX-FileCopyrightText: 2000, 2001, 2002, 2003 Cornelius Schumacher <schumacher@kde.org>
5   SPDX-FileCopyrightText: 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
6 
7   SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
8 */
9 
10 #include "koprefsdialogplugins.h"
11 #include "kocore.h"
12 #include "koprefs.h"
13 #include <CalendarSupport/KCalPrefs>
14 #include <KGuiItem>
15 #include <KLocalizedString>
16 #include <KMessageBox>
17 #include <KPluginFactory>
18 #include <KService>
19 #include <QAction>
20 #include <QGroupBox>
21 #include <QHeaderView>
22 #include <QLabel>
23 #include <QRadioButton>
24 #include <QToolButton>
25 #include <QTreeWidget>
26 #include <QVBoxLayout>
27 
28 class PluginItem : public QTreeWidgetItem
29 {
30 public:
PluginItem(QTreeWidget * parent,const KService::Ptr & service)31     PluginItem(QTreeWidget *parent, const KService::Ptr &service)
32         : QTreeWidgetItem(parent, {service->name()})
33         , mService(service)
34     {
35     }
36 
PluginItem(QTreeWidgetItem * parent,const KService::Ptr & service)37     PluginItem(QTreeWidgetItem *parent, const KService::Ptr &service)
38         : QTreeWidgetItem(parent, {service->name()})
39         , mService(service)
40     {
41     }
42 
service()43     KService::Ptr service()
44     {
45         return mService;
46     }
47 
48 private:
49     const KService::Ptr mService;
50 };
51 
52 Q_DECLARE_METATYPE(PluginItem *)
53 
54 K_PLUGIN_CLASS_WITH_JSON(KOPrefsDialogPlugins, "korganizer_configplugins.json")
55 
56 /**
57   Dialog for selecting and configuring KOrganizer plugins
58 */
KOPrefsDialogPlugins(QWidget * parent,const QVariantList & args)59 KOPrefsDialogPlugins::KOPrefsDialogPlugins(QWidget *parent, const QVariantList &args)
60     : KPrefsModule(KOPrefs::instance(), parent, args)
61 {
62     auto topTopLayout = new QVBoxLayout(this);
63     mTreeWidget = new QTreeWidget(this);
64     mTreeWidget->setColumnCount(2);
65     mTreeWidget->setHeaderHidden(true);
66     mTreeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
67     mTreeWidget->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
68     mTreeWidget->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
69     mTreeWidget->header()->setStretchLastSection(false);
70     topTopLayout->addWidget(mTreeWidget);
71 
72     mDescription = new QLabel(this);
73     mDescription->setAlignment(Qt::AlignVCenter);
74     mDescription->setWordWrap(true);
75     mDescription->setFrameShape(QLabel::Panel);
76     mDescription->setFrameShadow(QLabel::Sunken);
77     mDescription->setMinimumSize(QSize(0, 55));
78     QSizePolicy policy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
79     policy.setHorizontalStretch(0);
80     policy.setVerticalStretch(0);
81     policy.setHeightForWidth(mDescription->sizePolicy().hasHeightForWidth());
82     mDescription->setSizePolicy(policy);
83     topTopLayout->addWidget(mDescription);
84 
85     mPositioningGroupBox = new QGroupBox(i18nc("@title:group", "Position"), this);
86     // mPositionMonthTop = new QCheckBox(
87     // i18nc( "@option:check", "Show in the month view" ), mPositioningGroupBox );
88     mPositionAgendaTop = new QRadioButton(i18nc("@option:check", "Show at the top of the agenda views"), mPositioningGroupBox);
89     mPositionAgendaBottom = new QRadioButton(i18nc("@option:check", "Show at the bottom of the agenda views"), mPositioningGroupBox);
90     auto positioningLayout = new QVBoxLayout(mPositioningGroupBox);
91     // positioningLayout->addWidget( mPositionMonthTop );
92     positioningLayout->addWidget(mPositionAgendaTop);
93     positioningLayout->addWidget(mPositionAgendaBottom);
94     positioningLayout->addStretch(1);
95     topTopLayout->addWidget(mPositioningGroupBox);
96 
97     connect(mPositionAgendaTop, &QRadioButton::clicked, this, &KOPrefsDialogPlugins::positioningChanged);
98     connect(mPositionAgendaBottom, &QRadioButton::clicked, this, &KOPrefsDialogPlugins::positioningChanged);
99 
100     connect(mTreeWidget, &QTreeWidget::itemSelectionChanged, this, &KOPrefsDialogPlugins::selectionChanged);
101     connect(mTreeWidget, &QTreeWidget::itemChanged, this, &KOPrefsDialogPlugins::selectionChanged);
102     connect(mTreeWidget, &QTreeWidget::itemClicked, this, &KOPrefsDialogPlugins::slotWidChanged);
103 
104     load();
105 
106     selectionChanged();
107 }
108 
~KOPrefsDialogPlugins()109 KOPrefsDialogPlugins::~KOPrefsDialogPlugins()
110 {
111     delete mDecorations;
112 }
113 
usrReadConfig()114 void KOPrefsDialogPlugins::usrReadConfig()
115 {
116     mTreeWidget->clear();
117     KService::List plugins = KOCore::self()->availableCalendarDecorations();
118 
119     EventViews::PrefsPtr viewPrefs = KOPrefs::instance()->eventViewsPreferences();
120 
121     QStringList selectedPlugins = viewPrefs->selectedPlugins();
122 
123     mDecorations = new QTreeWidgetItem(mTreeWidget, QStringList(i18nc("@title:group", "Calendar Decorations")));
124 
125     KService::List::ConstIterator it;
126     KService::List::ConstIterator end(plugins.constEnd());
127 
128     for (it = plugins.constBegin(); it != end; ++it) {
129         PluginItem *item = nullptr;
130         if ((*it)->hasServiceType(EventViews::CalendarDecoration::Decoration::serviceType())) {
131             item = new PluginItem(mDecorations, *it);
132         } else {
133             continue;
134         }
135         if (selectedPlugins.contains((*it)->desktopEntryName())) {
136             item->setCheckState(0, Qt::Checked);
137         } else {
138             item->setCheckState(0, Qt::Unchecked);
139         }
140         const QVariant variant = (*it)->property(QStringLiteral("X-KDE-KOrganizer-HasSettings"));
141         const bool hasSettings = (variant.isValid() && variant.toBool());
142         if (hasSettings) {
143             auto but = new QToolButton(mTreeWidget);
144             auto act = new QAction(but);
145             const QString decoration = (*it)->desktopEntryName();
146             act->setData(QVariant::fromValue<PluginItem *>(item));
147             but->setDefaultAction(act);
148             but->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
149             but->setFixedWidth(28);
150             but->setToolTip(i18nc("@action", "Configure"));
151             but->setAutoFillBackground(true);
152             but->setEnabled(true);
153             mTreeWidget->setItemWidget(item, 1, but);
154             connect(but, &QToolButton::triggered, this, &KOPrefsDialogPlugins::configureClicked);
155         }
156     }
157 
158     mDecorations->setExpanded(true);
159 
160     const auto monthViewTop = KOPrefs::instance()->decorationsAtMonthViewTop();
161     mDecorationsAtMonthViewTop = QSet<QString>(monthViewTop.begin(), monthViewTop.end());
162     const auto agendaViewTop = viewPrefs->decorationsAtAgendaViewTop();
163     mDecorationsAtAgendaViewTop = QSet<QString>(agendaViewTop.begin(), agendaViewTop.end());
164     const auto agendaViewBottom = viewPrefs->decorationsAtAgendaViewBottom();
165     mDecorationsAtAgendaViewBottom = QSet<QString>(agendaViewBottom.begin(), agendaViewBottom.end());
166 }
167 
usrWriteConfig()168 void KOPrefsDialogPlugins::usrWriteConfig()
169 {
170     QStringList selectedPlugins;
171 
172     for (int i = 0; i < mTreeWidget->topLevelItemCount(); ++i) {
173         QTreeWidgetItem *serviceTypeGroup = mTreeWidget->topLevelItem(i);
174         for (int j = 0; j < serviceTypeGroup->childCount(); ++j) {
175             auto item = static_cast<PluginItem *>(serviceTypeGroup->child(j));
176             if (item->checkState(0) == Qt::Checked) {
177                 selectedPlugins.append(item->service()->desktopEntryName());
178             }
179         }
180     }
181     EventViews::PrefsPtr viewPrefs = KOPrefs::instance()->eventViewsPreferences();
182     viewPrefs->setSelectedPlugins(selectedPlugins);
183 
184     KOPrefs::instance()->setDecorationsAtMonthViewTop(mDecorationsAtMonthViewTop.values());
185     viewPrefs->setDecorationsAtAgendaViewTop(mDecorationsAtAgendaViewTop.values());
186     viewPrefs->setDecorationsAtAgendaViewBottom(mDecorationsAtAgendaViewBottom.values());
187 }
188 
configureClicked(QAction * action)189 void KOPrefsDialogPlugins::configureClicked(QAction *action)
190 {
191     if (!action) {
192         return;
193     }
194 
195     auto item = action->data().value<PluginItem *>();
196 
197     if (!item) {
198         return;
199     }
200 
201     EventViews::CalendarDecoration::Decoration *plugin = KOCore::self()->loadCalendarDecoration(item->service());
202 
203     if (plugin) {
204         plugin->configure(this);
205         delete plugin;
206 
207         slotWidChanged();
208     } else {
209         KMessageBox::sorry(this, i18nc("@info", "Unable to configure this plugin"), QStringLiteral("PluginConfigUnable"));
210     }
211 }
212 
positioningChanged()213 void KOPrefsDialogPlugins::positioningChanged()
214 {
215     if (mTreeWidget->selectedItems().count() != 1) {
216         return;
217     }
218 
219     PluginItem *item = dynamic_cast<PluginItem *>(mTreeWidget->selectedItems().last());
220     if (!item) {
221         return;
222     }
223 
224     QString decoration = item->service()->desktopEntryName();
225 
226     /*if ( mPositionMonthTop->checkState() == Qt::Checked ) {
227       if ( !mDecorationsAtMonthViewTop.contains( decoration ) ) {
228         mDecorationsAtMonthViewTop.insert( decoration );
229       }
230     } else {
231       mDecorationsAtMonthViewTop.remove( decoration );
232     }*/
233 
234     if (mPositionAgendaTop->isChecked()) {
235         if (!mDecorationsAtAgendaViewTop.contains(decoration)) {
236             mDecorationsAtAgendaViewTop.insert(decoration);
237         }
238     } else {
239         mDecorationsAtAgendaViewTop.remove(decoration);
240     }
241 
242     if (mPositionAgendaBottom->isChecked()) {
243         if (!mDecorationsAtAgendaViewBottom.contains(decoration)) {
244             mDecorationsAtAgendaViewBottom.insert(decoration);
245         }
246     } else {
247         mDecorationsAtAgendaViewBottom.remove(decoration);
248     }
249 
250     slotWidChanged();
251 }
252 
selectionChanged()253 void KOPrefsDialogPlugins::selectionChanged()
254 {
255     mPositioningGroupBox->hide();
256     // mPositionMonthTop->setChecked( false );
257     mPositionAgendaTop->setChecked(false);
258     mPositionAgendaBottom->setChecked(false);
259 
260     if (mTreeWidget->selectedItems().count() != 1) {
261         mDescription->setText(QString());
262         return;
263     }
264 
265     PluginItem *item = dynamic_cast<PluginItem *>(mTreeWidget->selectedItems().last());
266     if (!item) {
267         mDescription->setText(QString());
268         return;
269     }
270 
271     mDescription->setText(item->service()->comment());
272 
273     if (item->service()->hasServiceType(EventViews::CalendarDecoration::Decoration::serviceType())) {
274         bool hasPosition = false;
275         QString decoration = item->service()->desktopEntryName();
276         /*if ( mDecorationsAtMonthViewTop.contains( decoration ) ) {
277           mPositionMonthTop->setChecked( true );
278           hasPosition = true;
279         }*/
280         if (mDecorationsAtAgendaViewTop.contains(decoration)) {
281             mPositionAgendaTop->setChecked(true);
282             hasPosition = true;
283         }
284         if (mDecorationsAtAgendaViewBottom.contains(decoration)) {
285             mPositionAgendaBottom->setChecked(true);
286             hasPosition = true;
287         }
288 
289         if (!hasPosition) {
290             // no position has been selected, so default to Agenda Top
291             mDecorationsAtAgendaViewTop << decoration;
292             mPositionAgendaTop->setChecked(true);
293         }
294 
295         mPositioningGroupBox->setEnabled(item->checkState(0) == Qt::Checked);
296         mPositioningGroupBox->show();
297     }
298 
299     slotWidChanged();
300 }
301 
302 #include "koprefsdialogplugins.moc"
303