SVN_SILENT made messages (after extraction)
[kdepim.git] / korganizer / kcmdesignerfields.cpp
blobeac983409ef814662374b5dee795cb900019c67b
1 /*
2 This file is part of KOrganizer.
4 Copyright (c) 2004 Tobias Koenig <tokoe@kde.org>
5 Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
23 #include "kcmdesignerfields.h"
25 #include <KAboutData>
26 #include "korganizer_debug.h"
27 #include <KDirWatch>
28 #include <QFileDialog>
29 #include <KMessageBox>
30 #include <KRun>
31 #include <KShell>
32 #include <KStandardDirs>
33 #include <KIO/Job>
34 #include <KIO/NetAccess>
35 #include <KLocalizedString>
36 #include <QDialog>
37 #include <KGlobal>
38 #include <KFileDialog>
40 #include <QGroupBox>
41 #include <QHBoxLayout>
42 #include <QHeaderView>
43 #include <QLabel>
44 #include <QPushButton>
45 #include <QTreeWidget>
46 #include <QUiLoader>
47 #include <QWhatsThis>
48 #include <QStandardPaths>
49 #include <QDir>
50 #include <KConfigGroup>
52 class PageItem : public QTreeWidgetItem
54 public:
55 PageItem(QTreeWidget *parent, const QString &path)
56 : QTreeWidgetItem(parent),
57 mPath(path), mIsActive(false)
59 setFlags(flags() | Qt::ItemIsUserCheckable);
60 setCheckState(0, Qt::Unchecked);
61 mName = path.mid(path.lastIndexOf(QLatin1Char('/')) + 1);
63 QFile f(mPath);
64 if (!f.open(QFile::ReadOnly)) {
65 return;
67 QUiLoader builder;
68 QWidget *wdg = builder.load(&f, 0);
69 f.close();
70 if (wdg) {
71 setText(0, wdg->windowTitle());
73 QPixmap pm = QPixmap::grabWidget(wdg);
74 QImage img = pm.toImage().scaled(300, 300, Qt::KeepAspectRatio, Qt::SmoothTransformation);
75 mPreview = QPixmap::fromImage(img);
77 QMap<QString, QString> allowedTypes;
78 allowedTypes.insert(QLatin1String("QLineEdit"), i18n("Text"));
79 allowedTypes.insert(QLatin1String("QTextEdit"), i18n("Text"));
80 allowedTypes.insert(QLatin1String("QSpinBox"), i18n("Numeric Value"));
81 allowedTypes.insert(QLatin1String("QCheckBox"), i18n("Boolean"));
82 allowedTypes.insert(QLatin1String("QComboBox"), i18n("Selection"));
83 allowedTypes.insert(QLatin1String("QDateTimeEdit"), i18n("Date & Time"));
84 allowedTypes.insert(QLatin1String("KLineEdit"), i18n("Text"));
85 allowedTypes.insert(QLatin1String("KTextEdit"), i18n("Text"));
86 allowedTypes.insert(QLatin1String("KDateTimeWidget"), i18n("Date & Time"));
87 allowedTypes.insert(QLatin1String("KDatePicker"), i18n("Date"));
89 QList<QWidget *> list = wdg->findChildren<QWidget *>();
90 QWidget *it;
91 Q_FOREACH (it, list) {
92 if (allowedTypes.contains(QLatin1String(it->metaObject()->className()))) {
93 QString name = it->objectName();
94 if (name.startsWith(QLatin1String("X_"))) {
95 new QTreeWidgetItem(this, QStringList()
96 << name
97 << allowedTypes[ QLatin1String(it->metaObject()->className()) ]
98 << QLatin1String(it->metaObject()->className())
99 << it->whatsThis());
107 QString name() const
109 return mName;
112 QString path() const
114 return mPath;
117 QPixmap preview()
119 return mPreview;
122 void setIsActive(bool isActive)
124 mIsActive = isActive;
127 bool isActive() const
129 return mIsActive;
132 bool isOn() const
134 return checkState(0) == Qt::Checked;
137 private:
138 QString mName;
139 QString mPath;
140 QPixmap mPreview;
141 bool mIsActive;
144 KCMDesignerFields::KCMDesignerFields(QWidget *parent,
145 const QVariantList &args)
146 : KCModule(parent, args),
147 mPageView(0),
148 mPagePreview(0),
149 mPageDetails(0),
150 mDeleteButton(0),
151 mImportButton(0),
152 mDesignerButton(0)
154 KAboutData *about = new KAboutData(QStringLiteral("KCMDesignerfields"),
155 i18n("KCMDesignerfields"),
156 QString(),
157 i18n("Qt Designer Fields Dialog"),
158 KAboutLicense::LGPL,
159 i18n("(c) 2004 Tobias Koenig"));
160 about->addAuthor(ki18n("Tobias Koenig").toString(), QString(), QStringLiteral("tokoe@kde.org"));
161 about->addAuthor(ki18n("Cornelius Schumacher").toString(), QString(), QStringLiteral("schumacher@kde.org"));
162 setAboutData(about);
165 void KCMDesignerFields::delayedInit()
167 qCDebug(KORGANIZER_LOG) << "KCMDesignerFields::delayedInit()";
169 initGUI();
171 connect(mPageView, &QTreeWidget::itemSelectionChanged, this, &KCMDesignerFields::updatePreview);
172 connect(mPageView, &QTreeWidget::itemClicked, this, &KCMDesignerFields::itemClicked);
174 connect(mDeleteButton, &QPushButton::clicked, this, &KCMDesignerFields::deleteFile);
175 connect(mImportButton, &QPushButton::clicked, this, &KCMDesignerFields::importFile);
176 connect(mDesignerButton, &QPushButton::clicked, this, &KCMDesignerFields::startDesigner);
178 load();
180 // Install a dirwatcher that will detect newly created or removed designer files
181 KDirWatch *dw = new KDirWatch(this);
182 QDir().mkpath(localUiDir());
183 dw->addDir(localUiDir(), KDirWatch::WatchFiles);
184 connect(dw, &KDirWatch::created, this, &KCMDesignerFields::rebuildList);
185 connect(dw, &KDirWatch::deleted, this, &KCMDesignerFields::rebuildList);
186 connect(dw, &KDirWatch::dirty, this, &KCMDesignerFields::rebuildList);
189 void KCMDesignerFields::deleteFile()
191 foreach (QTreeWidgetItem *item, mPageView->selectedItems()) {
192 PageItem *pageItem = static_cast<PageItem *>(item->parent() ? item->parent() : item);
193 if (KMessageBox::warningContinueCancel(
194 this,
195 i18n("<qt>Do you really want to delete '<b>%1</b>'?</qt>",
196 pageItem->text(0)), QString(), KStandardGuiItem::del()) == KMessageBox::Continue) {
197 KIO::NetAccess::del(pageItem->path(), 0);
200 // The actual view refresh will be done automagically by the slots connected to kdirwatch
203 void KCMDesignerFields::importFile()
205 QUrl src = KFileDialog::getOpenFileName(QDir::homePath(),
206 i18n("*.ui|Designer Files"),
207 this, i18n("Import Page"));
208 QUrl dest = QUrl::fromLocalFile(localUiDir());
209 QDir().mkpath(localUiDir());
210 dest = dest.adjusted(QUrl::RemoveFilename);
211 dest.setPath(src.fileName());
212 KIO::Job *job = KIO::file_copy(src, dest, -1, KIO::Overwrite);
213 KIO::NetAccess::synchronousRun(job, this);
215 // The actual view refresh will be done automagically by the slots connected to kdirwatch
218 void KCMDesignerFields::loadUiFiles()
220 const QStringList list = KGlobal::dirs()->findAllResources("data", uiPath() + QLatin1String("/*.ui"),
221 KStandardDirs::Recursive |
222 KStandardDirs::NoDuplicates);
224 for (QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) {
225 new PageItem(mPageView, *it);
229 void KCMDesignerFields::rebuildList()
231 // If nothing is initialized there is no need to do something
232 if (mPageView) {
233 QStringList ai = saveActivePages();
234 updatePreview();
235 mPageView->clear();
236 loadUiFiles();
237 loadActivePages(ai);
241 void KCMDesignerFields::loadActivePages(const QStringList &ai)
243 QTreeWidgetItemIterator it(mPageView);
244 while (*it) {
245 if ((*it)->parent() == 0) {
246 PageItem *item = static_cast<PageItem *>(*it);
247 if (ai.contains(item->name())) {
248 item->setCheckState(0, Qt::Checked);
249 item->setIsActive(true);
253 ++it;
257 void KCMDesignerFields::load()
259 // see KCModule::showEvent()
260 if (!mPageView) {
261 delayedInit();
263 loadActivePages(readActivePages());
266 QStringList KCMDesignerFields::saveActivePages()
268 QTreeWidgetItemIterator it(mPageView, QTreeWidgetItemIterator::Checked |
269 QTreeWidgetItemIterator::Selectable);
271 QStringList activePages;
272 while (*it) {
273 if ((*it)->parent() == 0) {
274 PageItem *item = static_cast<PageItem *>(*it);
275 activePages.append(item->name());
278 ++it;
281 return activePages;
284 void KCMDesignerFields::save()
286 writeActivePages(saveActivePages());
289 void KCMDesignerFields::defaults()
293 void KCMDesignerFields::initGUI()
295 QVBoxLayout *layout = new QVBoxLayout(this);
297 bool noDesigner = QStandardPaths::findExecutable(QLatin1String("designer")).isEmpty();
299 if (noDesigner) {
300 QString txt =
301 i18n("<qt><b>Warning:</b> Qt Designer could not be found. It is probably not "
302 "installed. You will only be able to import existing designer files.</qt>");
303 QLabel *lbl = new QLabel(txt, this);
304 layout->addWidget(lbl);
307 QHBoxLayout *hbox = new QHBoxLayout();
308 layout->addLayout(hbox);
310 mPageView = new QTreeWidget(this);
311 mPageView->setHeaderLabel(i18n("Available Pages"));
312 mPageView->setRootIsDecorated(true);
313 mPageView->setAllColumnsShowFocus(true);
314 mPageView->header()->setResizeMode(QHeaderView::Stretch);
315 hbox->addWidget(mPageView);
317 QGroupBox *box = new QGroupBox(i18n("Preview of Selected Page"), this);
318 QVBoxLayout *boxLayout = new QVBoxLayout(box);
320 mPagePreview = new QLabel(box);
321 mPagePreview->setMinimumWidth(300);
322 boxLayout->addWidget(mPagePreview);
324 mPageDetails = new QLabel(box);
325 boxLayout->addWidget(mPageDetails);
326 boxLayout->addStretch(1);
328 hbox->addWidget(box);
330 loadUiFiles();
332 hbox = new QHBoxLayout();
333 layout->addLayout(hbox);
335 QString cwHowto =
336 i18n("<qt><p>This section allows you to add your own GUI"
337 " Elements ('<i>Widgets</i>') to store your own values"
338 " into %1. Proceed as described below:</p>"
339 "<ol>"
340 "<li>Click on '<i>Edit with Qt Designer</i>'</li>"
341 "<li>In the dialog, select '<i>Widget</i>', then click <i>OK</i></li>"
342 "<li>Add your widgets to the form</li>"
343 "<li>Save the file in the directory proposed by Qt Designer</li>"
344 "<li>Close Qt Designer</li>"
345 "</ol>"
346 "<p>In case you already have a designer file (*.ui) located"
347 " somewhere on your hard disk, simply choose '<i>Import Page</i>'</p>"
348 "<p><b>Important:</b> The name of each input widget you place within"
349 " the form must start with '<i>X_</i>'; so if you want the widget to"
350 " correspond to your custom entry '<i>X-Foo</i>', set the widget's"
351 " <i>name</i> property to '<i>X_Foo</i>'.</p>"
352 "<p><b>Important:</b> The widget will edit custom fields with an"
353 " application name of %2. To change the application name"
354 " to be edited, set the widget name in Qt Designer.</p></qt>",
355 applicationName(), applicationName());
357 QLabel *activeLabel = new QLabel(
358 i18n("<a href=\"whatsthis:%1\">How does this work?</a>", cwHowto), this);
359 activeLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse |
360 Qt::LinksAccessibleByKeyboard);
361 connect(activeLabel, &QLabel::linkActivated, this, &KCMDesignerFields::showWhatsThis);
362 activeLabel->setContextMenuPolicy(Qt::NoContextMenu);
363 hbox->addWidget(activeLabel);
365 // ### why is this needed? Looks like a KActiveLabel bug...
366 activeLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
368 hbox->addStretch(1);
370 mDeleteButton = new QPushButton(i18n("Delete Page"), this);
371 mDeleteButton->setEnabled(false);
372 hbox->addWidget(mDeleteButton);
373 mImportButton = new QPushButton(i18n("Import Page..."), this);
374 hbox->addWidget(mImportButton);
375 mDesignerButton = new QPushButton(i18n("Edit with Qt Designer..."), this);
376 hbox->addWidget(mDesignerButton);
378 if (noDesigner) {
379 mDesignerButton->setEnabled(false);
383 void KCMDesignerFields::updatePreview()
385 QTreeWidgetItem *item = 0;
386 if (mPageView->selectedItems().size() == 1) {
387 item = mPageView->selectedItems().first();
389 bool widgetItemSelected = false;
391 if (item) {
392 if (item->parent()) {
393 QString details = QStringLiteral("<qt><table>"
394 "<tr><td align=\"right\"><b>%1</b></td><td>%2</td></tr>"
395 "<tr><td align=\"right\"><b>%3</b></td><td>%4</td></tr>"
396 "<tr><td align=\"right\"><b>%5</b></td><td>%6</td></tr>"
397 "<tr><td align=\"right\"><b>%7</b></td><td>%8</td></tr>"
398 "</table></qt>")
399 .arg(i18n("Key:"))
400 .arg(item->text(0).replace(QLatin1String("X_"), QLatin1String("X-")))
401 .arg(i18n("Type:"))
402 .arg(item->text(1))
403 .arg(i18n("Classname:"))
404 .arg(item->text(2))
405 .arg(i18n("Description:"))
406 .arg(item->text(3));
408 mPageDetails->setText(details);
410 PageItem *pageItem = static_cast<PageItem *>(item->parent());
411 mPagePreview->setWindowIcon(pageItem->preview());
412 } else {
413 mPageDetails->setText(QString());
415 PageItem *pageItem = static_cast<PageItem *>(item);
416 mPagePreview->setWindowIcon(pageItem->preview());
418 widgetItemSelected = true;
421 mPagePreview->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
422 } else {
423 mPagePreview->setWindowIcon(QPixmap());
424 mPagePreview->setFrameStyle(0);
425 mPageDetails->setText(QString());
428 mDeleteButton->setEnabled(widgetItemSelected);
431 void KCMDesignerFields::itemClicked(QTreeWidgetItem *item)
433 if (!item || item->parent() != 0) {
434 return;
437 PageItem *pageItem = static_cast<PageItem *>(item);
439 if (pageItem->isOn() != pageItem->isActive()) {
440 emit changed(true);
441 pageItem->setIsActive(pageItem->isOn());
445 void KCMDesignerFields::startDesigner()
447 QString cmdLine = QLatin1String("designer");
449 // check if path exists and create one if not.
450 QString cepPath = localUiDir();
451 if (!KGlobal::dirs()->exists(cepPath)) {
452 KIO::NetAccess::mkdir(cepPath, this);
455 // finally jump there
456 QDir::setCurrent(QLatin1String(cepPath.toLocal8Bit()));
458 QTreeWidgetItem *item = 0;
459 if (mPageView->selectedItems().size() == 1) {
460 item = mPageView->selectedItems().first();
462 if (item) {
463 PageItem *pageItem = static_cast<PageItem *>(item->parent() ? item->parent() : item);
464 cmdLine += QLatin1Char(' ') + KShell::quoteArg(pageItem->path());
467 KRun::runCommand(cmdLine, topLevelWidget());
470 void KCMDesignerFields::showWhatsThis(const QString &href)
472 if (href.startsWith(QLatin1String("whatsthis:"))) {
473 QPoint pos = QCursor::pos();
474 QWhatsThis::showText(pos, href.mid(10), this);