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 <kstandarddirs.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 
54 using namespace KPIM;
55 
56 class 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 
129 KCMDesignerFields::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 
144 void 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 
173 void 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 
186 void 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 
197 void 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 
205 void KCMDesignerFields::rebuildList()
206 {
207  TQStringList ai = saveActivePages();
208  updatePreview( 0 );
209  mPageView->clear();
210  loadUiFiles();
211  loadActivePages(ai);
212 }
213 
214 void 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 
230 void KCMDesignerFields::load()
231 {
232  loadActivePages( readActivePages() );
233 }
234 
235 TQStringList 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 
253 void KCMDesignerFields::save()
254 {
255  writeActivePages( saveActivePages() );
256 }
257 
258 void KCMDesignerFields::defaults()
259 {
260 }
261 
262 void 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 
351 void 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 
395 void 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 
408 void 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.