kcmdesignerfields.cpp
00001 /* 00002 This file is part of libkdepim. 00003 00004 Copyright (c) 2004 Tobias Koenig <tokoe@kde.org> 00005 Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Library General Public 00009 License as published by the Free Software Foundation; either 00010 version 2 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Library General Public License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to 00019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 Boston, MA 02110-1301, USA. 00021 */ 00022 00023 #include <unistd.h> 00024 00025 #include <tqimage.h> 00026 #include <tqlabel.h> 00027 #include <tqlayout.h> 00028 #include <tqobjectlist.h> 00029 #include <tqpixmap.h> 00030 #include <tqpushbutton.h> 00031 #include <tqwhatsthis.h> 00032 #include <tqgroupbox.h> 00033 #include <tqwidgetfactory.h> 00034 #include <tqregexp.h> 00035 #include <tqtimer.h> 00036 00037 #include <kaboutdata.h> 00038 #include <kdebug.h> 00039 #include <kdialog.h> 00040 #include <kglobal.h> 00041 #include <klistview.h> 00042 #include <klocale.h> 00043 #include <krun.h> 00044 #include <kstandarddirs.h> 00045 #include <kactivelabel.h> 00046 #include <kdirwatch.h> 00047 #include <kfiledialog.h> 00048 #include <kmessagebox.h> 00049 #include <kprocess.h> 00050 #include <kio/netaccess.h> 00051 00052 #include "kcmdesignerfields.h" 00053 00054 using namespace KPIM; 00055 00056 class PageItem : public TQCheckListItem 00057 { 00058 public: 00059 PageItem( TQListView *parent, const TQString &path ) 00060 : TQCheckListItem( parent, "", TQCheckListItem::CheckBox ), 00061 mPath( path ), mIsActive( false ) 00062 { 00063 mName = path.mid( path.findRev( '/' ) + 1 ); 00064 00065 TQWidget *wdg = TQWidgetFactory::create( mPath, 0, 0 ); 00066 if ( wdg ) { 00067 setText( 0, wdg->caption() ); 00068 00069 TQPixmap pm = TQPixmap::grabWidget( wdg ); 00070 TQImage img = pm.convertToImage().smoothScale( 300, 300, TQ_ScaleMin ); 00071 mPreview = img; 00072 00073 TQObjectList *list = wdg->queryList( TQWIDGET_OBJECT_NAME_STRING ); 00074 TQObjectListIt it( *list ); 00075 00076 TQMap<TQString, TQString> allowedTypes; 00077 allowedTypes.insert( TQLINEEDIT_OBJECT_NAME_STRING, i18n( "Text" ) ); 00078 allowedTypes.insert( TQTEXTEDIT_OBJECT_NAME_STRING, i18n( "Text" ) ); 00079 allowedTypes.insert( TQSPINBOX_OBJECT_NAME_STRING, i18n( "Numeric Value" ) ); 00080 allowedTypes.insert( TQCHECKBOX_OBJECT_NAME_STRING, i18n( "Boolean" ) ); 00081 allowedTypes.insert( TQCOMBOBOX_OBJECT_NAME_STRING, i18n( "Selection" ) ); 00082 allowedTypes.insert( TQDATETIMEEDIT_OBJECT_NAME_STRING, i18n( "Date & Time" ) ); 00083 allowedTypes.insert( "KLineEdit", i18n( "Text" ) ); 00084 allowedTypes.insert( "KDateTimeWidget", i18n( "Date & Time" ) ); 00085 allowedTypes.insert( "KDatePicker", i18n( "Date" ) ); 00086 00087 while ( it.current() ) { 00088 if ( allowedTypes.find( it.current()->className() ) != allowedTypes.end() ) { 00089 TQString name = it.current()->name(); 00090 if ( name.startsWith( "X_" ) ) { 00091 new TQListViewItem( this, name, 00092 allowedTypes[ it.current()->className() ], 00093 it.current()->className(), 00094 TQWhatsThis::textFor( TQT_TQWIDGET( it.current() ) ) ); 00095 } 00096 } 00097 00098 ++it; 00099 } 00100 00101 delete list; 00102 } 00103 } 00104 00105 TQString name() const { return mName; } 00106 TQString path() const { return mPath; } 00107 00108 TQPixmap preview() 00109 { 00110 return mPreview; 00111 } 00112 00113 void setIsActive( bool isActive ) { mIsActive = isActive; } 00114 bool isActive() const { return mIsActive; } 00115 00116 protected: 00117 void paintBranches( TQPainter *p, const TQColorGroup & cg, int w, int y, int h ) 00118 { 00119 TQListViewItem::paintBranches( p, cg, w, y, h ); 00120 } 00121 00122 private: 00123 TQString mName; 00124 TQString mPath; 00125 TQPixmap mPreview; 00126 bool mIsActive; 00127 }; 00128 00129 KCMDesignerFields::KCMDesignerFields( TQWidget *parent, const char *name ) 00130 : KCModule( parent, name ) 00131 { 00132 TQTimer::singleShot( 0, this, TQT_SLOT( delayedInit() ) ); 00133 00134 KAboutData *about = new KAboutData( I18N_NOOP( "KCMDesignerfields" ), 00135 I18N_NOOP( "TQt Designer Fields Dialog" ), 00136 0, 0, KAboutData::License_LGPL, 00137 I18N_NOOP( "(c), 2004 Tobias Koenig" ) ); 00138 00139 about->addAuthor( "Tobias Koenig", 0, "tokoe@kde.org" ); 00140 about->addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" ); 00141 setAboutData( about ); 00142 } 00143 00144 void KCMDesignerFields::delayedInit() 00145 { 00146 kdDebug() << "KCMDesignerFields::delayedInit()" << endl; 00147 00148 initGUI(); 00149 00150 connect( mPageView, TQT_SIGNAL( selectionChanged( TQListViewItem* ) ), 00151 this, TQT_SLOT( updatePreview( TQListViewItem* ) ) ); 00152 connect( mPageView, TQT_SIGNAL( clicked( TQListViewItem* ) ), 00153 this, TQT_SLOT( itemClicked( TQListViewItem* ) ) ); 00154 00155 connect( mDeleteButton, TQT_SIGNAL( clicked() ), 00156 this, TQT_SLOT( deleteFile() ) ); 00157 connect( mImportButton, TQT_SIGNAL( clicked() ), 00158 this, TQT_SLOT( importFile() ) ); 00159 connect( mDesignerButton, TQT_SIGNAL( clicked() ), 00160 this, TQT_SLOT( startDesigner() ) ); 00161 00162 load(); 00163 00164 // Install a dirwatcher that will detect newly created or removed designer files 00165 KDirWatch *dw = new KDirWatch( TQT_TQOBJECT(this) ); 00166 KStandardDirs::makeDir(localUiDir()); 00167 dw->addDir( localUiDir(), true ); 00168 connect( dw, TQT_SIGNAL( created(const TQString&) ), TQT_SLOT( rebuildList() ) ); 00169 connect( dw, TQT_SIGNAL( deleted(const TQString&) ), TQT_SLOT( rebuildList() ) ); 00170 connect( dw, TQT_SIGNAL( dirty(const TQString&) ), TQT_SLOT( rebuildList() ) ); 00171 } 00172 00173 void KCMDesignerFields::deleteFile() 00174 { 00175 TQListViewItem *item = mPageView->selectedItem(); 00176 if ( item ) { 00177 PageItem *pageItem = static_cast<PageItem*>( item->parent() ? item->parent() : item ); 00178 if (KMessageBox::warningContinueCancel(this, 00179 i18n( "<qt>Do you really want to delete '<b>%1</b>'?</qt>").arg( pageItem->text(0) ), "", KStdGuiItem::del() ) 00180 == KMessageBox::Continue) 00181 KIO::NetAccess::del( pageItem->path(), 0 ); 00182 } 00183 // The actual view refresh will be done automagically by the slots connected to kdirwatch 00184 } 00185 00186 void KCMDesignerFields::importFile() 00187 { 00188 KURL src = KFileDialog::getOpenFileName( TQDir::homeDirPath(), i18n("*.ui|Designer Files"), 00189 this, i18n("Import Page") ); 00190 KURL dest = localUiDir(); 00191 dest.setFileName(src.fileName()); 00192 KIO::NetAccess::file_copy( src, dest, -1, true, false, this ); 00193 // The actual view refresh will be done automagically by the slots connected to kdirwatch 00194 } 00195 00196 00197 void KCMDesignerFields::loadUiFiles() 00198 { 00199 TQStringList list = KGlobal::dirs()->findAllResources( "data", uiPath() + "/*.ui", true, true ); 00200 for ( TQStringList::iterator it = list.begin(); it != list.end(); ++it ) { 00201 new PageItem( mPageView, *it ); 00202 } 00203 } 00204 00205 void KCMDesignerFields::rebuildList() 00206 { 00207 TQStringList ai = saveActivePages(); 00208 updatePreview( 0 ); 00209 mPageView->clear(); 00210 loadUiFiles(); 00211 loadActivePages(ai); 00212 } 00213 00214 void KCMDesignerFields::loadActivePages(const TQStringList& ai) 00215 { 00216 TQListViewItemIterator it( mPageView ); 00217 while ( it.current() ) { 00218 if ( it.current()->parent() == 0 ) { 00219 PageItem *item = static_cast<PageItem*>( it.current() ); 00220 if ( ai.find( item->name() ) != ai.end() ) { 00221 item->setOn( true ); 00222 item->setIsActive( true ); 00223 } 00224 } 00225 00226 ++it; 00227 } 00228 } 00229 00230 void KCMDesignerFields::load() 00231 { 00232 loadActivePages( readActivePages() ); 00233 } 00234 00235 TQStringList KCMDesignerFields::saveActivePages() 00236 { 00237 TQListViewItemIterator it( mPageView, TQListViewItemIterator::Checked | 00238 TQListViewItemIterator::Selectable ); 00239 00240 TQStringList activePages; 00241 while ( it.current() ) { 00242 if ( it.current()->parent() == 0 ) { 00243 PageItem *item = static_cast<PageItem*>( it.current() ); 00244 activePages.append( item->name() ); 00245 } 00246 00247 ++it; 00248 } 00249 00250 return activePages; 00251 } 00252 00253 void KCMDesignerFields::save() 00254 { 00255 writeActivePages( saveActivePages() ); 00256 } 00257 00258 void KCMDesignerFields::defaults() 00259 { 00260 } 00261 00262 void KCMDesignerFields::initGUI() 00263 { 00264 TQVBoxLayout *layout = new TQVBoxLayout( this, KDialog::marginHint(), 00265 KDialog::spacingHint() ); 00266 00267 bool noDesigner = KStandardDirs::findExe("designer").isEmpty(); 00268 00269 if ( noDesigner ) 00270 { 00271 TQString txt = 00272 i18n("<qt><b>Warning:</b> TQt Designer could not be found. It is probably not " 00273 "installed. You will only be able to import existing designer files.</qt>"); 00274 TQLabel *lbl = new TQLabel( txt, this ); 00275 layout->addWidget( lbl ); 00276 } 00277 00278 TQHBoxLayout *hbox = new TQHBoxLayout( layout, KDialog::spacingHint() ); 00279 00280 mPageView = new KListView( this ); 00281 mPageView->addColumn( i18n( "Available Pages" ) ); 00282 mPageView->setRootIsDecorated( true ); 00283 mPageView->setAllColumnsShowFocus( true ); 00284 mPageView->setFullWidth( true ); 00285 hbox->addWidget( mPageView ); 00286 00287 TQGroupBox *box = new TQGroupBox(1, Qt::Horizontal, i18n("Preview of Selected Page"), this ); 00288 00289 mPagePreview = new TQLabel( box ); 00290 mPagePreview->setMinimumWidth( 300 ); 00291 00292 mPageDetails = new TQLabel( box ); 00293 00294 hbox->addWidget( box ); 00295 00296 loadUiFiles(); 00297 00298 hbox = new TQHBoxLayout( layout, KDialog::spacingHint() ); 00299 00300 TQString cwHowto = i18n("<qt><p>This section allows you to add your own GUI" 00301 " Elements ('<i>Widgets</i>') to store your own values" 00302 " into %1. Proceed as described below:</p>" 00303 "<ol>" 00304 "<li>Click on '<i>Edit with TQt Designer</i>'" 00305 "<li>In the dialog, select '<i>Widget</i>', then click <i>OK</i>" 00306 "<li>Add your widgets to the form" 00307 "<li>Save the file in the directory proposed by TQt Designer" 00308 "<li>Close TQt Designer" 00309 "</ol>" 00310 "<p>In case you already have a designer file (*.ui) located" 00311 " somewhere on your hard disk, simply choose '<i>Import Page</i>'</p>" 00312 "<p><b>Important:</b> The name of each input widget you place within" 00313 " the form must start with '<i>X_</i>'; so if you want the widget to" 00314 " correspond to your custom entry '<i>X-Foo</i>', set the widget's" 00315 " <i>name</i> property to '<i>X_Foo</i>'.</p>" 00316 "<p><b>Important:</b> The widget will edit custom fields with an" 00317 " application name of %2. To change the application name" 00318 " to be edited, set the widget name in TQt Designer.</p></qt>" ) 00319 .arg( applicationName(), applicationName() ); 00320 00321 KActiveLabel *activeLabel = new KActiveLabel( 00322 i18n( "<a href=\"whatsthis:%1\">How does this work?</a>" ).arg(cwHowto), this ); 00323 hbox->addWidget( activeLabel ); 00324 00325 // ### why is this needed? Looks like a KActiveLabel bug... 00326 activeLabel->setSizePolicy( TQSizePolicy::Preferred, TQSizePolicy::Maximum ); 00327 00328 hbox->addStretch( 1 ); 00329 00330 mDeleteButton = new TQPushButton( i18n( "Delete Page" ), this); 00331 mDeleteButton->setEnabled( false ); 00332 hbox->addWidget( mDeleteButton ); 00333 mImportButton = new TQPushButton( i18n( "Import Page..." ), this); 00334 hbox->addWidget( mImportButton ); 00335 mDesignerButton = new TQPushButton( i18n( "Edit with TQt Designer..." ), this ); 00336 hbox->addWidget( mDesignerButton ); 00337 00338 if ( noDesigner ) 00339 mDesignerButton->setEnabled( false ); 00340 00341 // FIXME: Why do I have to call show() for all widgets? A this->show() doesn't 00342 // seem to work. 00343 mPageView->show(); 00344 box->show(); 00345 activeLabel->show(); 00346 mDeleteButton->show(); 00347 mImportButton->show(); 00348 mDesignerButton->show(); 00349 } 00350 00351 void KCMDesignerFields::updatePreview( TQListViewItem *item ) 00352 { 00353 bool widgetItemSelected = false; 00354 00355 if ( item ) { 00356 if ( item->parent() ) { 00357 TQString details = TQString( "<qt><table>" 00358 "<tr><td align=\"right\"><b>%1</b></td><td>%2</td></tr>" 00359 "<tr><td align=\"right\"><b>%3</b></td><td>%4</td></tr>" 00360 "<tr><td align=\"right\"><b>%5</b></td><td>%6</td></tr>" 00361 "<tr><td align=\"right\"><b>%7</b></td><td>%8</td></tr>" 00362 "</table></qt>" ) 00363 .arg( i18n( "Key:" ) ) 00364 .arg( item->text( 0 ).replace("X_","X-") ) 00365 .arg( i18n( "Type:" ) ) 00366 .arg( item->text( 1 ) ) 00367 .arg( i18n( "Classname:" ) ) 00368 .arg( item->text( 2 ) ) 00369 .arg( i18n( "Description:" ) ) 00370 .arg( item->text( 3 ) ); 00371 00372 mPageDetails->setText( details ); 00373 00374 PageItem *pageItem = static_cast<PageItem*>( item->parent() ); 00375 mPagePreview->setPixmap( pageItem->preview() ); 00376 } else { 00377 mPageDetails->setText( TQString() ); 00378 00379 PageItem *pageItem = static_cast<PageItem*>( item ); 00380 mPagePreview->setPixmap( pageItem->preview() ); 00381 00382 widgetItemSelected = true; 00383 } 00384 00385 mPagePreview->setFrameStyle( TQFrame::Panel | TQFrame::Sunken ); 00386 } else { 00387 mPagePreview->setPixmap( TQPixmap() ); 00388 mPagePreview->setFrameStyle( 0 ); 00389 mPageDetails->setText( TQString() ); 00390 } 00391 00392 mDeleteButton->setEnabled( widgetItemSelected ); 00393 } 00394 00395 void KCMDesignerFields::itemClicked( TQListViewItem *item ) 00396 { 00397 if ( !item || item->parent() != 0 ) 00398 return; 00399 00400 PageItem *pageItem = static_cast<PageItem*>( item ); 00401 00402 if ( pageItem->isOn() != pageItem->isActive() ) { 00403 emit changed( true ); 00404 pageItem->setIsActive( pageItem->isOn() ); 00405 } 00406 } 00407 00408 void KCMDesignerFields::startDesigner() 00409 { 00410 TQString cmdLine = "designer"; 00411 00412 // check if path exists and create one if not. 00413 TQString cepPath = localUiDir(); 00414 if( !KGlobal::dirs()->exists(cepPath) ) { 00415 KIO::NetAccess::mkdir( cepPath, this ); 00416 } 00417 00418 // finally jump there 00419 chdir(cepPath.local8Bit()); 00420 00421 TQListViewItem *item = mPageView->selectedItem(); 00422 if ( item ) { 00423 PageItem *pageItem = static_cast<PageItem*>( item->parent() ? item->parent() : item ); 00424 cmdLine += " " + KProcess::quote( pageItem->path() ); 00425 } 00426 00427 KRun::runCommand( cmdLine ); 00428 } 00429 00430 #include "kcmdesignerfields.moc"