libtdepim

kcmdesignerfields.cpp
1/*
2 This file is part of libtdepim.
3
4 Copyright (c) 2004 Tobias Koenig <tokoe@kde.org>
5 Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>
6
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.
11
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.
16
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.
21*/
22
23#include <unistd.h>
24
25#include <tqimage.h>
26#include <tqlabel.h>
27#include <tqlayout.h>
28#include <tqobjectlist.h>
29#include <tqpixmap.h>
30#include <tqpushbutton.h>
31#include <tqwhatsthis.h>
32#include <tqgroupbox.h>
33#include <tqwidgetfactory.h>
34#include <tqregexp.h>
35#include <tqtimer.h>
36
37#include <tdeaboutdata.h>
38#include <kdebug.h>
39#include <kdialog.h>
40#include <tdeglobal.h>
41#include <tdelistview.h>
42#include <tdelocale.h>
43#include <krun.h>
44#include <tdestandarddirs.h>
45#include <kactivelabel.h>
46#include <kdirwatch.h>
47#include <tdefiledialog.h>
48#include <tdemessagebox.h>
49#include <tdeprocess.h>
50#include <tdeio/netaccess.h>
51
52#include "kcmdesignerfields.h"
53
54using namespace KPIM;
55
56class PageItem : public TQCheckListItem
57{
58 public:
59 PageItem( TQListView *parent, const TQString &path )
60 : TQCheckListItem( parent, "", TQCheckListItem::CheckBox ),
61 mPath( path ), mIsActive( false )
62 {
63 mName = path.mid( path.findRev( '/' ) + 1 );
64
65 TQWidget *wdg = TQWidgetFactory::create( mPath, 0, 0 );
66 if ( wdg ) {
67 setText( 0, wdg->caption() );
68
69 TQPixmap pm = TQPixmap::grabWidget( wdg );
70 TQImage img = pm.convertToImage().smoothScale( 300, 300, TQImage::ScaleMin );
71 mPreview = img;
72
73 TQObjectList *list = wdg->queryList( "TQWidget" );
74 TQObjectListIt it( *list );
75
76 TQMap<TQString, TQString> allowedTypes;
77 allowedTypes.insert( "TQLineEdit", i18n( "Text" ) );
78 allowedTypes.insert( "TQTextEdit", i18n( "Text" ) );
79 allowedTypes.insert( "TQSpinBox", i18n( "Numeric Value" ) );
80 allowedTypes.insert( "TQCheckBox", i18n( "Boolean" ) );
81 allowedTypes.insert( "TQComboBox", i18n( "Selection" ) );
82 allowedTypes.insert( "TQDateTimeEdit", i18n( "Date & Time" ) );
83 allowedTypes.insert( "KLineEdit", i18n( "Text" ) );
84 allowedTypes.insert( "KDateTimeWidget", i18n( "Date & Time" ) );
85 allowedTypes.insert( "KDatePicker", i18n( "Date" ) );
86
87 while ( it.current() ) {
88 if ( allowedTypes.find( it.current()->className() ) != allowedTypes.end() ) {
89 TQString name = it.current()->name();
90 if ( name.startsWith( "X_" ) ) {
91 new TQListViewItem( this, name,
92 allowedTypes[ it.current()->className() ],
93 it.current()->className(),
94 TQWhatsThis::textFor( static_cast<TQWidget*>( it.current() ) ) );
95 }
96 }
97
98 ++it;
99 }
100
101 delete list;
102 }
103 }
104
105 TQString name() const { return mName; }
106 TQString path() const { return mPath; }
107
108 TQPixmap preview()
109 {
110 return mPreview;
111 }
112
113 void setIsActive( bool isActive ) { mIsActive = isActive; }
114 bool isActive() const { return mIsActive; }
115
116 protected:
117 void paintBranches( TQPainter *p, const TQColorGroup & cg, int w, int y, int h )
118 {
119 TQListViewItem::paintBranches( p, cg, w, y, h );
120 }
121
122 private:
123 TQString mName;
124 TQString mPath;
125 TQPixmap mPreview;
126 bool mIsActive;
127};
128
129KCMDesignerFields::KCMDesignerFields( TQWidget *parent, const char *name )
130 : TDECModule( parent, name )
131{
132 TQTimer::singleShot( 0, this, TQ_SLOT( delayedInit() ) );
133
134 TDEAboutData *about = new TDEAboutData( I18N_NOOP( "KCMDesignerfields" ),
135 I18N_NOOP( "TQt Designer Fields Dialog" ),
136 0, 0, TDEAboutData::License_LGPL,
137 I18N_NOOP( "(c), 2004 Tobias Koenig" ) );
138
139 about->addAuthor( "Tobias Koenig", 0, "tokoe@kde.org" );
140 about->addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" );
141 setAboutData( about );
142}
143
144void KCMDesignerFields::delayedInit()
145{
146 kdDebug() << "KCMDesignerFields::delayedInit()" << endl;
147
148 initGUI();
149
150 connect( mPageView, TQ_SIGNAL( selectionChanged( TQListViewItem* ) ),
151 this, TQ_SLOT( updatePreview( TQListViewItem* ) ) );
152 connect( mPageView, TQ_SIGNAL( clicked( TQListViewItem* ) ),
153 this, TQ_SLOT( itemClicked( TQListViewItem* ) ) );
154
155 connect( mDeleteButton, TQ_SIGNAL( clicked() ),
156 this, TQ_SLOT( deleteFile() ) );
157 connect( mImportButton, TQ_SIGNAL( clicked() ),
158 this, TQ_SLOT( importFile() ) );
159 connect( mDesignerButton, TQ_SIGNAL( clicked() ),
160 this, TQ_SLOT( startDesigner() ) );
161
162 load();
163
164 // Install a dirwatcher that will detect newly created or removed designer files
165 KDirWatch *dw = new KDirWatch( this );
166 TDEStandardDirs::makeDir(localUiDir());
167 dw->addDir( localUiDir(), true );
168 connect( dw, TQ_SIGNAL( created(const TQString&) ), TQ_SLOT( rebuildList() ) );
169 connect( dw, TQ_SIGNAL( deleted(const TQString&) ), TQ_SLOT( rebuildList() ) );
170 connect( dw, TQ_SIGNAL( dirty(const TQString&) ), TQ_SLOT( rebuildList() ) );
171}
172
173void KCMDesignerFields::deleteFile()
174{
175 TQListViewItem *item = mPageView->selectedItem();
176 if ( item ) {
177 PageItem *pageItem = static_cast<PageItem*>( item->parent() ? item->parent() : item );
178 if (KMessageBox::warningContinueCancel(this,
179 i18n( "<qt>Do you really want to delete '<b>%1</b>'?</qt>").arg( pageItem->text(0) ), "", KStdGuiItem::del() )
180 == KMessageBox::Continue)
181 TDEIO::NetAccess::del( pageItem->path(), 0 );
182 }
183 // The actual view refresh will be done automagically by the slots connected to kdirwatch
184}
185
186void KCMDesignerFields::importFile()
187{
188 KURL src = KFileDialog::getOpenFileName( TQDir::homeDirPath(), i18n("*.ui|Designer Files"),
189 this, i18n("Import Page") );
190 KURL dest = localUiDir();
191 dest.setFileName(src.fileName());
192 TDEIO::NetAccess::file_copy( src, dest, -1, true, false, this );
193 // The actual view refresh will be done automagically by the slots connected to kdirwatch
194}
195
196
197void KCMDesignerFields::loadUiFiles()
198{
199 TQStringList list = TDEGlobal::dirs()->findAllResources( "data", uiPath() + "/*.ui", true, true );
200 for ( TQStringList::iterator it = list.begin(); it != list.end(); ++it ) {
201 new PageItem( mPageView, *it );
202 }
203}
204
205void KCMDesignerFields::rebuildList()
206{
207 TQStringList ai = saveActivePages();
208 updatePreview( 0 );
209 mPageView->clear();
210 loadUiFiles();
211 loadActivePages(ai);
212}
213
214void KCMDesignerFields::loadActivePages(const TQStringList& ai)
215{
216 TQListViewItemIterator it( mPageView );
217 while ( it.current() ) {
218 if ( it.current()->parent() == 0 ) {
219 PageItem *item = static_cast<PageItem*>( it.current() );
220 if ( ai.find( item->name() ) != ai.end() ) {
221 item->setOn( true );
222 item->setIsActive( true );
223 }
224 }
225
226 ++it;
227 }
228}
229
230void KCMDesignerFields::load()
231{
232 loadActivePages( readActivePages() );
233}
234
235TQStringList KCMDesignerFields::saveActivePages()
236{
237 TQListViewItemIterator it( mPageView, TQListViewItemIterator::Checked |
238 TQListViewItemIterator::Selectable );
239
240 TQStringList activePages;
241 while ( it.current() ) {
242 if ( it.current()->parent() == 0 ) {
243 PageItem *item = static_cast<PageItem*>( it.current() );
244 activePages.append( item->name() );
245 }
246
247 ++it;
248 }
249
250 return activePages;
251}
252
253void KCMDesignerFields::save()
254{
255 writeActivePages( saveActivePages() );
256}
257
258void KCMDesignerFields::defaults()
259{
260}
261
262void KCMDesignerFields::initGUI()
263{
264 TQVBoxLayout *layout = new TQVBoxLayout( this, KDialog::marginHint(),
265 KDialog::spacingHint() );
266
267 bool noDesigner = TDEStandardDirs::findExe("designer").isEmpty();
268
269 if ( noDesigner )
270 {
271 TQString txt =
272 i18n("<qt><b>Warning:</b> TQt Designer could not be found. It is probably not "
273 "installed. You will only be able to import existing designer files.</qt>");
274 TQLabel *lbl = new TQLabel( txt, this );
275 layout->addWidget( lbl );
276 }
277
278 TQHBoxLayout *hbox = new TQHBoxLayout( layout, KDialog::spacingHint() );
279
280 mPageView = new TDEListView( this );
281 mPageView->addColumn( i18n( "Available Pages" ) );
282 mPageView->setRootIsDecorated( true );
283 mPageView->setAllColumnsShowFocus( true );
284 mPageView->setFullWidth( true );
285 hbox->addWidget( mPageView );
286
287 TQGroupBox *box = new TQGroupBox(1, TQt::Horizontal, i18n("Preview of Selected Page"), this );
288
289 mPagePreview = new TQLabel( box );
290 mPagePreview->setMinimumWidth( 300 );
291
292 mPageDetails = new TQLabel( box );
293
294 hbox->addWidget( box );
295
296 loadUiFiles();
297
298 hbox = new TQHBoxLayout( layout, KDialog::spacingHint() );
299
300 TQString cwHowto = i18n("<qt><p>This section allows you to add your own GUI"
301 " Elements ('<i>Widgets</i>') to store your own values"
302 " into %1. Proceed as described below:</p>"
303 "<ol>"
304 "<li>Click on '<i>Edit with TQt Designer</i>'"
305 "<li>In the dialog, select '<i>Widget</i>', then click <i>OK</i>"
306 "<li>Add your widgets to the form"
307 "<li>Save the file in the directory proposed by TQt Designer"
308 "<li>Close TQt Designer"
309 "</ol>"
310 "<p>In case you already have a designer file (*.ui) located"
311 " somewhere on your hard disk, simply choose '<i>Import Page</i>'</p>"
312 "<p><b>Important:</b> The name of each input widget you place within"
313 " the form must start with '<i>X_</i>'; so if you want the widget to"
314 " correspond to your custom entry '<i>X-Foo</i>', set the widget's"
315 " <i>name</i> property to '<i>X_Foo</i>'.</p>"
316 "<p><b>Important:</b> The widget will edit custom fields with an"
317 " application name of %2. To change the application name"
318 " to be edited, set the widget name in TQt Designer.</p></qt>" )
319 .arg( applicationName(), applicationName() );
320
321 KActiveLabel *activeLabel = new KActiveLabel(
322 i18n( "<a href=\"whatsthis:%1\">How does this work?</a>" ).arg(cwHowto), this );
323 hbox->addWidget( activeLabel );
324
325 // ### why is this needed? Looks like a KActiveLabel bug...
326 activeLabel->setSizePolicy( TQSizePolicy::Preferred, TQSizePolicy::Maximum );
327
328 hbox->addStretch( 1 );
329
330 mDeleteButton = new TQPushButton( i18n( "Delete Page" ), this);
331 mDeleteButton->setEnabled( false );
332 hbox->addWidget( mDeleteButton );
333 mImportButton = new TQPushButton( i18n( "Import Page..." ), this);
334 hbox->addWidget( mImportButton );
335 mDesignerButton = new TQPushButton( i18n( "Edit with TQt Designer..." ), this );
336 hbox->addWidget( mDesignerButton );
337
338 if ( noDesigner )
339 mDesignerButton->setEnabled( false );
340
341 // FIXME: Why do I have to call show() for all widgets? A this->show() doesn't
342 // seem to work.
343 mPageView->show();
344 box->show();
345 activeLabel->show();
346 mDeleteButton->show();
347 mImportButton->show();
348 mDesignerButton->show();
349}
350
351void KCMDesignerFields::updatePreview( TQListViewItem *item )
352{
353 bool widgetItemSelected = false;
354
355 if ( item ) {
356 if ( item->parent() ) {
357 TQString details = TQString( "<qt><table>"
358 "<tr><td align=\"right\"><b>%1</b></td><td>%2</td></tr>"
359 "<tr><td align=\"right\"><b>%3</b></td><td>%4</td></tr>"
360 "<tr><td align=\"right\"><b>%5</b></td><td>%6</td></tr>"
361 "<tr><td align=\"right\"><b>%7</b></td><td>%8</td></tr>"
362 "</table></qt>" )
363 .arg( i18n( "Key:" ) )
364 .arg( item->text( 0 ).replace("X_","X-") )
365 .arg( i18n( "Type:" ) )
366 .arg( item->text( 1 ) )
367 .arg( i18n( "Classname:" ) )
368 .arg( item->text( 2 ) )
369 .arg( i18n( "Description:" ) )
370 .arg( item->text( 3 ) );
371
372 mPageDetails->setText( details );
373
374 PageItem *pageItem = static_cast<PageItem*>( item->parent() );
375 mPagePreview->setPixmap( pageItem->preview() );
376 } else {
377 mPageDetails->setText( TQString() );
378
379 PageItem *pageItem = static_cast<PageItem*>( item );
380 mPagePreview->setPixmap( pageItem->preview() );
381
382 widgetItemSelected = true;
383 }
384
385 mPagePreview->setFrameStyle( TQFrame::Panel | TQFrame::Sunken );
386 } else {
387 mPagePreview->setPixmap( TQPixmap() );
388 mPagePreview->setFrameStyle( 0 );
389 mPageDetails->setText( TQString() );
390 }
391
392 mDeleteButton->setEnabled( widgetItemSelected );
393}
394
395void KCMDesignerFields::itemClicked( TQListViewItem *item )
396{
397 if ( !item || item->parent() != 0 )
398 return;
399
400 PageItem *pageItem = static_cast<PageItem*>( item );
401
402 if ( pageItem->isOn() != pageItem->isActive() ) {
403 emit changed( true );
404 pageItem->setIsActive( pageItem->isOn() );
405 }
406}
407
408void KCMDesignerFields::startDesigner()
409{
410 TQString cmdLine = "designer";
411
412 // check if path exists and create one if not.
413 TQString cepPath = localUiDir();
414 if( !TDEGlobal::dirs()->exists(cepPath) ) {
415 TDEIO::NetAccess::mkdir( cepPath, this );
416 }
417
418 // finally jump there
419 chdir(cepPath.local8Bit());
420
421 TQListViewItem *item = mPageView->selectedItem();
422 if ( item ) {
423 PageItem *pageItem = static_cast<PageItem*>( item->parent() ? item->parent() : item );
424 cmdLine += " " + TDEProcess::quote( pageItem->path() );
425 }
426
427 KRun::runCommand( cmdLine );
428}
429
430#include "kcmdesignerfields.moc"
TDEPIM classes for drag and drop of mails.