libtdepim

kcmdesignerfields.cpp

00001 /*
00002     This file is part of libtdepim.
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 <tdeaboutdata.h>
00038 #include <kdebug.h>
00039 #include <kdialog.h>
00040 #include <tdeglobal.h>
00041 #include <tdelistview.h>
00042 #include <tdelocale.h>
00043 #include <krun.h>
00044 #include <kstandarddirs.h>
00045 #include <kactivelabel.h>
00046 #include <kdirwatch.h>
00047 #include <tdefiledialog.h>
00048 #include <tdemessagebox.h>
00049 #include <kprocess.h>
00050 #include <tdeio/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   : TDECModule( parent, name )
00131 {
00132   TQTimer::singleShot( 0, this, TQT_SLOT( delayedInit() ) );
00133   
00134   TDEAboutData *about = new TDEAboutData( I18N_NOOP( "KCMDesignerfields" ),
00135                                       I18N_NOOP( "TQt Designer Fields Dialog" ),
00136                                       0, 0, TDEAboutData::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   TDEStandardDirs::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       TDEIO::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   TDEIO::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 = TDEGlobal::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 = TDEStandardDirs::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 TDEListView( 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( !TDEGlobal::dirs()->exists(cepPath) ) {
00415     TDEIO::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 += " " + TDEProcess::quote( pageItem->path() );
00425   }
00426 
00427   KRun::runCommand( cmdLine );
00428 }
00429 
00430 #include "kcmdesignerfields.moc"