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"
26 #include "korganizer_debug.h"
28 #include <QFileDialog>
29 #include <KMessageBox>
32 #include <KStandardDirs>
34 #include <KIO/NetAccess>
35 #include <KLocalizedString>
38 #include <KFileDialog>
41 #include <QHBoxLayout>
42 #include <QHeaderView>
44 #include <QPushButton>
45 #include <QTreeWidget>
48 #include <QStandardPaths>
50 #include <KConfigGroup>
52 class PageItem
: public QTreeWidgetItem
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);
64 if (!f
.open(QFile::ReadOnly
)) {
68 QWidget
*wdg
= builder
.load(&f
, 0);
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
*>();
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()
97 << allowedTypes
[ QLatin1String(it
->metaObject()->className()) ]
98 << QLatin1String(it
->metaObject()->className())
122 void setIsActive(bool isActive
)
124 mIsActive
= isActive
;
127 bool isActive() const
134 return checkState(0) == Qt::Checked
;
144 KCMDesignerFields::KCMDesignerFields(QWidget
*parent
,
145 const QVariantList
&args
)
146 : KCModule(parent
, args
),
154 KAboutData
*about
= new KAboutData(QStringLiteral("KCMDesignerfields"),
155 i18n("KCMDesignerfields"),
157 i18n("Qt Designer Fields Dialog"),
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"));
165 void KCMDesignerFields::delayedInit()
167 qCDebug(KORGANIZER_LOG
) << "KCMDesignerFields::delayedInit()";
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
);
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(
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
233 QStringList ai
= saveActivePages();
241 void KCMDesignerFields::loadActivePages(const QStringList
&ai
)
243 QTreeWidgetItemIterator
it(mPageView
);
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);
257 void KCMDesignerFields::load()
259 // see KCModule::showEvent()
263 loadActivePages(readActivePages());
266 QStringList
KCMDesignerFields::saveActivePages()
268 QTreeWidgetItemIterator
it(mPageView
, QTreeWidgetItemIterator::Checked
|
269 QTreeWidgetItemIterator::Selectable
);
271 QStringList activePages
;
273 if ((*it
)->parent() == 0) {
274 PageItem
*item
= static_cast<PageItem
*>(*it
);
275 activePages
.append(item
->name());
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();
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
);
332 hbox
= new QHBoxLayout();
333 layout
->addLayout(hbox
);
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>"
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>"
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
);
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
);
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;
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>"
400 .arg(item
->text(0).replace(QLatin1String("X_"), QLatin1String("X-")))
403 .arg(i18n("Classname:"))
405 .arg(i18n("Description:"))
408 mPageDetails
->setText(details
);
410 PageItem
*pageItem
= static_cast<PageItem
*>(item
->parent());
411 mPagePreview
->setWindowIcon(pageItem
->preview());
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
);
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) {
437 PageItem
*pageItem
= static_cast<PageItem
*>(item
);
439 if (pageItem
->isOn() != pageItem
->isActive()) {
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();
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);