/* This file is part of libtdepim. Copyright (c) 2004 Tobias Koenig <tokoe@kde.org> Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <unistd.h> #include <tqimage.h> #include <tqlabel.h> #include <tqlayout.h> #include <tqobjectlist.h> #include <tqpixmap.h> #include <tqpushbutton.h> #include <tqwhatsthis.h> #include <tqgroupbox.h> #include <tqwidgetfactory.h> #include <tqregexp.h> #include <tqtimer.h> #include <tdeaboutdata.h> #include <kdebug.h> #include <kdialog.h> #include <tdeglobal.h> #include <tdelistview.h> #include <tdelocale.h> #include <krun.h> #include <kstandarddirs.h> #include <kactivelabel.h> #include <kdirwatch.h> #include <tdefiledialog.h> #include <tdemessagebox.h> #include <kprocess.h> #include <tdeio/netaccess.h> #include "kcmdesignerfields.h" using namespace KPIM; class PageItem : public TQCheckListItem { public: PageItem( TQListView *parent, const TQString &path ) : TQCheckListItem( parent, "", TQCheckListItem::CheckBox ), mPath( path ), mIsActive( false ) { mName = path.mid( path.findRev( '/' ) + 1 ); TQWidget *wdg = TQWidgetFactory::create( mPath, 0, 0 ); if ( wdg ) { setText( 0, wdg->caption() ); TQPixmap pm = TQPixmap::grabWidget( wdg ); TQImage img = pm.convertToImage().smoothScale( 300, 300, TQImage::ScaleMin ); mPreview = img; TQObjectList *list = wdg->queryList( "TQWidget" ); TQObjectListIt it( *list ); TQMap<TQString, TQString> allowedTypes; allowedTypes.insert( "TQLineEdit", i18n( "Text" ) ); allowedTypes.insert( "TQTextEdit", i18n( "Text" ) ); allowedTypes.insert( "TQSpinBox", i18n( "Numeric Value" ) ); allowedTypes.insert( "TQCheckBox", i18n( "Boolean" ) ); allowedTypes.insert( "TQComboBox", i18n( "Selection" ) ); allowedTypes.insert( "TQDateTimeEdit", i18n( "Date & Time" ) ); allowedTypes.insert( "KLineEdit", i18n( "Text" ) ); allowedTypes.insert( "KDateTimeWidget", i18n( "Date & Time" ) ); allowedTypes.insert( "KDatePicker", i18n( "Date" ) ); while ( it.current() ) { if ( allowedTypes.find( it.current()->className() ) != allowedTypes.end() ) { TQString name = it.current()->name(); if ( name.startsWith( "X_" ) ) { new TQListViewItem( this, name, allowedTypes[ it.current()->className() ], it.current()->className(), TQWhatsThis::textFor( static_cast<TQWidget*>( it.current() ) ) ); } } ++it; } delete list; } } TQString name() const { return mName; } TQString path() const { return mPath; } TQPixmap preview() { return mPreview; } void setIsActive( bool isActive ) { mIsActive = isActive; } bool isActive() const { return mIsActive; } protected: void paintBranches( TQPainter *p, const TQColorGroup & cg, int w, int y, int h ) { TQListViewItem::paintBranches( p, cg, w, y, h ); } private: TQString mName; TQString mPath; TQPixmap mPreview; bool mIsActive; }; KCMDesignerFields::KCMDesignerFields( TQWidget *parent, const char *name ) : TDECModule( parent, name ) { TQTimer::singleShot( 0, this, TQ_SLOT( delayedInit() ) ); TDEAboutData *about = new TDEAboutData( I18N_NOOP( "KCMDesignerfields" ), I18N_NOOP( "TQt Designer Fields Dialog" ), 0, 0, TDEAboutData::License_LGPL, I18N_NOOP( "(c), 2004 Tobias Koenig" ) ); about->addAuthor( "Tobias Koenig", 0, "tokoe@kde.org" ); about->addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" ); setAboutData( about ); } void KCMDesignerFields::delayedInit() { kdDebug() << "KCMDesignerFields::delayedInit()" << endl; initGUI(); connect( mPageView, TQ_SIGNAL( selectionChanged( TQListViewItem* ) ), this, TQ_SLOT( updatePreview( TQListViewItem* ) ) ); connect( mPageView, TQ_SIGNAL( clicked( TQListViewItem* ) ), this, TQ_SLOT( itemClicked( TQListViewItem* ) ) ); connect( mDeleteButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( deleteFile() ) ); connect( mImportButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( importFile() ) ); connect( mDesignerButton, TQ_SIGNAL( clicked() ), this, TQ_SLOT( startDesigner() ) ); load(); // Install a dirwatcher that will detect newly created or removed designer files KDirWatch *dw = new KDirWatch( this ); TDEStandardDirs::makeDir(localUiDir()); dw->addDir( localUiDir(), true ); connect( dw, TQ_SIGNAL( created(const TQString&) ), TQ_SLOT( rebuildList() ) ); connect( dw, TQ_SIGNAL( deleted(const TQString&) ), TQ_SLOT( rebuildList() ) ); connect( dw, TQ_SIGNAL( dirty(const TQString&) ), TQ_SLOT( rebuildList() ) ); } void KCMDesignerFields::deleteFile() { TQListViewItem *item = mPageView->selectedItem(); if ( item ) { PageItem *pageItem = static_cast<PageItem*>( item->parent() ? item->parent() : item ); if (KMessageBox::warningContinueCancel(this, i18n( "<qt>Do you really want to delete '<b>%1</b>'?</qt>").arg( pageItem->text(0) ), "", KStdGuiItem::del() ) == KMessageBox::Continue) TDEIO::NetAccess::del( pageItem->path(), 0 ); } // The actual view refresh will be done automagically by the slots connected to kdirwatch } void KCMDesignerFields::importFile() { KURL src = KFileDialog::getOpenFileName( TQDir::homeDirPath(), i18n("*.ui|Designer Files"), this, i18n("Import Page") ); KURL dest = localUiDir(); dest.setFileName(src.fileName()); TDEIO::NetAccess::file_copy( src, dest, -1, true, false, this ); // The actual view refresh will be done automagically by the slots connected to kdirwatch } void KCMDesignerFields::loadUiFiles() { TQStringList list = TDEGlobal::dirs()->findAllResources( "data", uiPath() + "/*.ui", true, true ); for ( TQStringList::iterator it = list.begin(); it != list.end(); ++it ) { new PageItem( mPageView, *it ); } } void KCMDesignerFields::rebuildList() { TQStringList ai = saveActivePages(); updatePreview( 0 ); mPageView->clear(); loadUiFiles(); loadActivePages(ai); } void KCMDesignerFields::loadActivePages(const TQStringList& ai) { TQListViewItemIterator it( mPageView ); while ( it.current() ) { if ( it.current()->parent() == 0 ) { PageItem *item = static_cast<PageItem*>( it.current() ); if ( ai.find( item->name() ) != ai.end() ) { item->setOn( true ); item->setIsActive( true ); } } ++it; } } void KCMDesignerFields::load() { loadActivePages( readActivePages() ); } TQStringList KCMDesignerFields::saveActivePages() { TQListViewItemIterator it( mPageView, TQListViewItemIterator::Checked | TQListViewItemIterator::Selectable ); TQStringList activePages; while ( it.current() ) { if ( it.current()->parent() == 0 ) { PageItem *item = static_cast<PageItem*>( it.current() ); activePages.append( item->name() ); } ++it; } return activePages; } void KCMDesignerFields::save() { writeActivePages( saveActivePages() ); } void KCMDesignerFields::defaults() { } void KCMDesignerFields::initGUI() { TQVBoxLayout *layout = new TQVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() ); bool noDesigner = TDEStandardDirs::findExe("designer").isEmpty(); if ( noDesigner ) { TQString txt = i18n("<qt><b>Warning:</b> TQt Designer could not be found. It is probably not " "installed. You will only be able to import existing designer files.</qt>"); TQLabel *lbl = new TQLabel( txt, this ); layout->addWidget( lbl ); } TQHBoxLayout *hbox = new TQHBoxLayout( layout, KDialog::spacingHint() ); mPageView = new TDEListView( this ); mPageView->addColumn( i18n( "Available Pages" ) ); mPageView->setRootIsDecorated( true ); mPageView->setAllColumnsShowFocus( true ); mPageView->setFullWidth( true ); hbox->addWidget( mPageView ); TQGroupBox *box = new TQGroupBox(1, TQt::Horizontal, i18n("Preview of Selected Page"), this ); mPagePreview = new TQLabel( box ); mPagePreview->setMinimumWidth( 300 ); mPageDetails = new TQLabel( box ); hbox->addWidget( box ); loadUiFiles(); hbox = new TQHBoxLayout( layout, KDialog::spacingHint() ); TQString cwHowto = i18n("<qt><p>This section allows you to add your own GUI" " Elements ('<i>Widgets</i>') to store your own values" " into %1. Proceed as described below:</p>" "<ol>" "<li>Click on '<i>Edit with TQt Designer</i>'" "<li>In the dialog, select '<i>Widget</i>', then click <i>OK</i>" "<li>Add your widgets to the form" "<li>Save the file in the directory proposed by TQt Designer" "<li>Close TQt Designer" "</ol>" "<p>In case you already have a designer file (*.ui) located" " somewhere on your hard disk, simply choose '<i>Import Page</i>'</p>" "<p><b>Important:</b> The name of each input widget you place within" " the form must start with '<i>X_</i>'; so if you want the widget to" " correspond to your custom entry '<i>X-Foo</i>', set the widget's" " <i>name</i> property to '<i>X_Foo</i>'.</p>" "<p><b>Important:</b> The widget will edit custom fields with an" " application name of %2. To change the application name" " to be edited, set the widget name in TQt Designer.</p></qt>" ) .arg( applicationName(), applicationName() ); KActiveLabel *activeLabel = new KActiveLabel( i18n( "<a href=\"whatsthis:%1\">How does this work?</a>" ).arg(cwHowto), this ); hbox->addWidget( activeLabel ); // ### why is this needed? Looks like a KActiveLabel bug... activeLabel->setSizePolicy( TQSizePolicy::Preferred, TQSizePolicy::Maximum ); hbox->addStretch( 1 ); mDeleteButton = new TQPushButton( i18n( "Delete Page" ), this); mDeleteButton->setEnabled( false ); hbox->addWidget( mDeleteButton ); mImportButton = new TQPushButton( i18n( "Import Page..." ), this); hbox->addWidget( mImportButton ); mDesignerButton = new TQPushButton( i18n( "Edit with TQt Designer..." ), this ); hbox->addWidget( mDesignerButton ); if ( noDesigner ) mDesignerButton->setEnabled( false ); // FIXME: Why do I have to call show() for all widgets? A this->show() doesn't // seem to work. mPageView->show(); box->show(); activeLabel->show(); mDeleteButton->show(); mImportButton->show(); mDesignerButton->show(); } void KCMDesignerFields::updatePreview( TQListViewItem *item ) { bool widgetItemSelected = false; if ( item ) { if ( item->parent() ) { TQString details = TQString( "<qt><table>" "<tr><td align=\"right\"><b>%1</b></td><td>%2</td></tr>" "<tr><td align=\"right\"><b>%3</b></td><td>%4</td></tr>" "<tr><td align=\"right\"><b>%5</b></td><td>%6</td></tr>" "<tr><td align=\"right\"><b>%7</b></td><td>%8</td></tr>" "</table></qt>" ) .arg( i18n( "Key:" ) ) .arg( item->text( 0 ).replace("X_","X-") ) .arg( i18n( "Type:" ) ) .arg( item->text( 1 ) ) .arg( i18n( "Classname:" ) ) .arg( item->text( 2 ) ) .arg( i18n( "Description:" ) ) .arg( item->text( 3 ) ); mPageDetails->setText( details ); PageItem *pageItem = static_cast<PageItem*>( item->parent() ); mPagePreview->setPixmap( pageItem->preview() ); } else { mPageDetails->setText( TQString() ); PageItem *pageItem = static_cast<PageItem*>( item ); mPagePreview->setPixmap( pageItem->preview() ); widgetItemSelected = true; } mPagePreview->setFrameStyle( TQFrame::Panel | TQFrame::Sunken ); } else { mPagePreview->setPixmap( TQPixmap() ); mPagePreview->setFrameStyle( 0 ); mPageDetails->setText( TQString() ); } mDeleteButton->setEnabled( widgetItemSelected ); } void KCMDesignerFields::itemClicked( TQListViewItem *item ) { if ( !item || item->parent() != 0 ) return; PageItem *pageItem = static_cast<PageItem*>( item ); if ( pageItem->isOn() != pageItem->isActive() ) { emit changed( true ); pageItem->setIsActive( pageItem->isOn() ); } } void KCMDesignerFields::startDesigner() { TQString cmdLine = "designer"; // check if path exists and create one if not. TQString cepPath = localUiDir(); if( !TDEGlobal::dirs()->exists(cepPath) ) { TDEIO::NetAccess::mkdir( cepPath, this ); } // finally jump there chdir(cepPath.local8Bit()); TQListViewItem *item = mPageView->selectedItem(); if ( item ) { PageItem *pageItem = static_cast<PageItem*>( item->parent() ? item->parent() : item ); cmdLine += " " + TDEProcess::quote( pageItem->path() ); } KRun::runCommand( cmdLine ); } #include "kcmdesignerfields.moc"