/* KPilot ** ** Copyright (C) 2001 by Dan Pilone ** Copyright (C) 2002-2004 by Adriaan de Groot ** Copyright (C) 2003-2004 Reinhold Kainhofer ** ** This file defines a .ui-based configuration dialog for conduits. */ /* ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program 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 General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program in a file called COPYING; if not, write to ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ** MA 02110-1301, USA. */ /* ** Bug reports and questions can be sent to kde-pim@kde.org */ #include "options.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "plugin.h" #include "kpilotConfig.h" #include "kpilotConfigDialog.h" #include "kpilotConfigWizard.h" #include "conduitConfigDialog.moc" #define CONDUIT_NAME (0) #define CONDUIT_COMMENT (1) #define CONDUIT_DESKTOP (2) #define CONDUIT_LIBRARY (3) #define CONDUIT_ORDER (4) extern "C" { KDE_EXPORT KCModule *create_kpilotconfig( TQWidget *parent, const char * ) { FUNCTIONSETUP; return new ConduitConfigWidget( parent, "kcmkpilotconfig" ); } KDE_EXPORT ConfigWizard *create_wizard(TQWidget *parent, int m) { FUNCTIONSETUP; return new ConfigWizard(parent,"Wizard", m); } } class ConduitTip : public TQToolTip { public: ConduitTip(TQListView *parent); virtual ~ConduitTip(); protected: virtual void maybeTip(const TQPoint &); TQListView *fListView; } ; ConduitTip::ConduitTip(TQListView *p) : TQToolTip(p->viewport(),0L), fListView(p) { FUNCTIONSETUP; } ConduitTip::~ConduitTip() { FUNCTIONSETUP; } /* virtual */ void ConduitTip::maybeTip(const TQPoint &p) { FUNCTIONSETUP; TQListViewItem *l = fListView->itemAt(p); if (!l) return; // ConduitListItem *q = static_cast(l); #ifdef DEBUG DEBUGKPILOT << fname << ": Tip over " << l->text(CONDUIT_NAME) << " with text " << l->text(CONDUIT_COMMENT) << endl; #endif TQString s = l->text(CONDUIT_COMMENT); if (s.isEmpty()) return; if (s.find(CSL1(""),0,false) == -1) { s.prepend(CSL1("")); s.append(CSL1("")); } tip(fListView->tqitemRect(l),s); } // implement our own check list items so we can detect if a given item was checked/unchecked. We need // this to prevent the modified signal if one only wants to display a conduit's config widget. Currently, // KListView doesn't provide any signal that indicates that the checked state of a checklist item was changed. class KPilotCheckListItem : public TQCheckListItem { public: KPilotCheckListItem ( TQListViewItem * parent, const TQString & text, Type tt = RadioButtonController ) : TQCheckListItem(parent, text, tt),mOriginalState(false) {} ~KPilotCheckListItem() {} void setOriginalState(bool state) { mOriginalState=state; setOn(state);} bool isOriginalState() { return isOn() == mOriginalState; } protected: bool mOriginalState; }; // Page numbers in the widget stack #define OLD_CONDUIT (1) #define BROKEN_CONDUIT (2) #define INTERNAL_CONDUIT (3) #define INTERNAL_EXPLN (4) #define CONDUIT_EXPLN (5) #define GENERAL_EXPLN (6) #define GENERAL_ABOUT (7) #define NEW_CONDUIT (8) /* ** Create a page in the widget stack @p parent on page @p pageno, ** bearing the given @p text. The remainder of the parameters are ** for esoteric things like: ** @p buttons set to non-null to include (and return) a TQHBox suitable ** for displaying a row of buttons in on the page. ** @p label set to non-null to return the TQLabel used to display @p text. */ static void addDescriptionPage(TQWidgetStack *parent, int pageno, const TQString &text, TQHBox **buttons = 0L, TQLabel **label = 0L) { TQVBox *v = new TQVBox(parent); TQLabel *l = 0L; v->setFrameShape(TQLabel::NoFrame); v->setMargin(SPACING); l = new TQLabel(v); l->setText(text); l->tqsetAlignment(TQt::AlignLeft | TQt::AlignVCenter | TQt::ExpandTabs | TQt::WordBreak); if (label) { *label = l; } if (buttons) { *buttons = new TQHBox(v); l = new TQLabel(v); } parent->addWidget(v,pageno); } ConduitConfigWidgetBase::ConduitConfigWidgetBase(TQWidget *parent, const char *n) : KCModule(parent, n), fConduitList(0L), fStack(0L), fConfigureButton(0L), fConfigureWizard(0L), fConfigureKontact(0L), fActionDescription(0L) { FUNCTIONSETUP; TQWidget *w = 0L; // For spacing purposes only. TQHBox *btns = 0L; TQHBoxLayout *mainLayout = new TQHBoxLayout(this); mainLayout->setSpacing(10); // Create the left hand column fConduitList = new TQListView(this ,"ConduitList"); fConduitList->addColumn(TQString()); fConduitList->header()->hide(); fConduitList->tqsetSizePolicy( TQSizePolicy(TQSizePolicy::Maximum, TQSizePolicy::Preferred)); mainLayout->addWidget(fConduitList); // Create the title TQVBoxLayout *vbox = new TQVBoxLayout(this, 0, KDialog::spacingHint()); // String below is just to make space; no need to translate. fTitleText = new TQLabel(CSL1("Conduit Setup - Addressbook"), this); TQFont titleFont(fTitleText->font()); titleFont.setBold(true); fTitleText->setFont(titleFont); vbox->addWidget(fTitleText, 0, AlignLeft); vbox->addWidget(new KSeparator(TQFrame::HLine|TQFrame::Plain, this)); // Right hand column fStack = new TQWidgetStack(this, "RightPart"); vbox->addWidget(fStack, 10); mainLayout->addLayout(vbox); // First page in stack (right hand column) addDescriptionPage(fStack,BROKEN_CONDUIT, i18n("This conduit appears to be broken and cannot " "be configured.")); // Second page, now with tqlayout in a single column // // Probably deprecated. // addDescriptionPage(fStack,OLD_CONDUIT, i18n("This is an old-style conduit."),&btns); w = new TQWidget(btns); btns->setStretchFactor(w,50); fConfigureButton = new TQPushButton(btns); fConfigureButton->setText(i18n("Configure...")); w = new TQWidget(btns); btns->setStretchFactor(w,50); // Page 3 addDescriptionPage(fStack,INTERNAL_CONDUIT, TQString(),0L,&fActionDescription); // Page 5 - explanation about conduits addDescriptionPage(fStack,CONDUIT_EXPLN, i18n("Conduits are external (possibly third-party) " "programs that perform synchronization actions. They may " "have individual configurations. Select a conduit to configure it, " "and enable it by clicking on its checkbox. " "")); // Page 6 - explanation about general setup addDescriptionPage(fStack,GENERAL_EXPLN, i18n("

The general portion of KPilot's setup " "contains settings for your hardware and the way KPilot " "should display your data. For the basic setup, which should fulfill " "the need of most users, just use the setup wizard below.

" "If you need some special settings, this dialog provides all the options " "for fine-tuning KPilot. But be warned: The HotSync settings are " "various esoteric things.

" "

You can enable an action or conduit by clicking on its checkbox. " "Checked conduits will be run during a HotSync. " "Select a conduit to configure it.

" "
"),&btns); w = new TQWidget(btns); btns->setStretchFactor(w,50); fConfigureWizard = new TQPushButton(i18n("Configuration Wizard"),btns); w = new TQWidget(btns); btns->setStretchFactor(w,50); fStack->addWidget(ConduitConfigBase::aboutPage(fStack,0L),GENERAL_ABOUT); } ConduitConfigWidget::ConduitConfigWidget(TQWidget *parent, const char *n, bool) : ConduitConfigWidgetBase(parent,n), fConfigure(0L), fCurrentConduit(0L), fGeneralPage(0L), fCurrentConfig(0L) { FUNCTIONSETUP; fConduitList->setSorting(-1); fConduitList->setRootIsDecorated(true); fConduitList->setTreeStepSize(10); // fConduitList->removeColumn(CONDUIT_COMMENT); fillLists(); fConduitList->resize(fConduitList->tqsizeHint()); fConduitList->setMinimumSize(fConduitList->tqsizeHint()); fConduitList->setColumnWidth(0, fConduitList->tqsizeHint().width()); fConduitList->setResizeMode(TQListView::AllColumns); fStack->resize(fStack->tqsizeHint()+TQSize(10,40)); fStack->setMinimumSize(fStack->tqsizeHint()+TQSize(10,40)); TQObject::connect(fConduitList, TQT_SIGNAL(selectionChanged(TQListViewItem *)), this,TQT_SLOT(selected(TQListViewItem *))); TQObject::connect(fConduitList, TQT_SIGNAL(clicked(TQListViewItem*)), this, TQT_SLOT(conduitsChanged(TQListViewItem*))); // Deprecated? TQObject::connect(fConfigureButton, TQT_SIGNAL(clicked()), this,TQT_SLOT(configure())); TQObject::connect(fConfigureWizard,TQT_SIGNAL(clicked()), this,TQT_SLOT(configureWizard())); fGeneralPage->setSelected(true); fConduitList->setCurrentItem(fGeneralPage); selected(fGeneralPage); (void) new ConduitTip(fConduitList); setButtons(Apply); } ConduitConfigWidget::~ConduitConfigWidget() { FUNCTIONSETUP; release(); } void ConduitConfigWidget::fillLists() { FUNCTIONSETUP; // 3 TQListViewItems for the three headings in the list TQListViewItem *general,*conduits; // And two generic pointers for the rest. TQListViewItem *q = 0L; KPilotCheckListItem *p = 0L; q = new TQListViewItem(fConduitList, i18n("About")); q->setText(CONDUIT_COMMENT, i18n("About KPilot. Credits.")); q->setText(CONDUIT_LIBRARY, CSL1("general_about")); conduits = new TQListViewItem(fConduitList, i18n("Conduits")); general = new TQListViewItem( fConduitList, i18n("General Setup" ) ); fGeneralPage = general; // Give them identifiers so they can be handled specially when selected. conduits->setText(CONDUIT_LIBRARY,CSL1("expln_conduits")); general->setText( CONDUIT_LIBRARY, CSL1("expln_general") ); general->setText( CONDUIT_COMMENT, i18n("General setup of KPilot (User name, port, general sync settings)") ); conduits->setText( CONDUIT_COMMENT, i18n("Actions for HotSync with individual configuration.")); conduits->setOpen(true); general->setOpen(true); // Create entries under general. #define CE(a,b,c) q = new TQListViewItem(general,a) ; \ q->setText(CONDUIT_COMMENT,b) ; \ q->setText(CONDUIT_LIBRARY,c) ; CE(i18n("Startup and Exit"), i18n("Behavior at startup and exit."), CSL1("general_startexit") ); CE(i18n("Viewers"), i18n("Viewer settings."), CSL1("general_view") ); CE(i18n("Backup"),i18n("Special settings for backup."),CSL1("general_backup")); CE(i18n("HotSync"),i18n("Special behavior during HotSync."),CSL1("general_sync")); CE(i18n("Device"),i18n("Hardware settings and startup and exit options."),CSL1("general_setup")); #undef CE // List of installed (enabled) actions and conduits. TQStringList potentiallyInstalled = KPilotSettings::installedConduits(); // Create internal conduits. // // #define IC(a,b,c) p = new KPilotCheckListItem(conduits,i18n(a),TQCheckListItem::CheckBox); \ p->setText(CONDUIT_COMMENT,i18n(c)); \ p->setText(CONDUIT_LIBRARY,CSL1("internal_" b)); \ p->setText(CONDUIT_DESKTOP,CSL1("internal_" b)); \ if (potentiallyInstalled.findIndex(p->text(CONDUIT_DESKTOP))>=0) \ p->setOriginalState(true); IC("Install Files","fileinstall", "Install files that are dragged to KPilot onto the handheld."); #undef IC KServiceTypeProfile::OfferList offers = KServiceTypeProfile::offers(CSL1("KPilotConduit")); TQValueListIterator < KServiceOffer > availList(offers.begin()); while (availList != offers.end()) { KSharedPtr < KService > o = (*availList).service(); #ifdef DEBUG DEBUGKPILOT << fname << ": " << o->desktopEntryName() << " = " << o->name() << endl; #endif if (!o->exec().isEmpty()) { WARNINGKPILOT << "Old-style conduit found " << o->name() << endl; } p = new KPilotCheckListItem(conduits, o->name(), TQCheckListItem::CheckBox); p->setMultiLinesEnabled(true); p->setText(CONDUIT_COMMENT,o->comment()); p->setText(CONDUIT_DESKTOP,o->desktopEntryName()); p->setText(CONDUIT_LIBRARY,o->library()); if (potentiallyInstalled.findIndex(o->desktopEntryName()) < 0) { p->setOriginalState(false); } else { p->setOriginalState(true); } ++availList; } } static void dumpConduitInfo(const KLibrary *lib) { #ifdef DEBUG FUNCTIONSETUP; DEBUGKPILOT << "Plugin version = " << PluginUtility::pluginVersion(lib) << endl; DEBUGKPILOT << "Plugin id = " << PluginUtility::pluginVersionString(lib) << endl; #endif } static ConduitConfigBase *handleGeneralPages(TQWidget *w, TQListViewItem *p) { ConduitConfigBase *o = 0L; TQString s = p->text(CONDUIT_LIBRARY) ; if (s.startsWith(CSL1("general_setup"))) { o = new DeviceConfigPage( w, "generalSetup" ); } else if (s.startsWith(CSL1("general_sync"))) { o = new SyncConfigPage( w, "syncSetup" ); } else if (s.startsWith(CSL1("general_view"))) { o = new ViewersConfigPage( w, "viewSetup" ); } else if (s.startsWith(CSL1("general_startexit"))) { o = new StartExitConfigPage(w,"startSetup"); } else if (s.startsWith(CSL1("general_backup"))) { o = new BackupConfigPage(w,"backupSetup"); } return o; } void ConduitConfigWidget::loadAndConfigure(TQListViewItem *p) // ,bool exec) { FUNCTIONSETUP; if (!p) { #ifdef DEBUG DEBUGKPILOT << fname << ": Executed NULL conduit?" << endl; #endif fStack->raiseWidget(GENERAL_EXPLN); return; } TQString libraryName = p->text(CONDUIT_LIBRARY); #ifdef DEBUG DEBUGKPILOT << fname << ": Executing conduit " << p->text(CONDUIT_NAME) << " (library " << libraryName << ")" << endl; #endif if (libraryName.isEmpty()) { fStack->raiseWidget(BROKEN_CONDUIT); warnNoExec(p); return; } if (libraryName.startsWith(CSL1("internal_"))) { fStack->raiseWidget(INTERNAL_CONDUIT); fActionDescription->setText( i18n("This is an internal action which has no " "configuration options. " "The action's description is: %1 " "").tqarg(p->text(CONDUIT_COMMENT))); return; } if (libraryName == CSL1("expln_conduits")) { fStack->raiseWidget(CONDUIT_EXPLN); return; } if (libraryName == CSL1("expln_general")) { fStack->raiseWidget(GENERAL_EXPLN); return; } if (libraryName == CSL1("general_about")) { fStack->raiseWidget(GENERAL_ABOUT); return; } TQObject *o = 0L; // Page 4: General setup if (libraryName.startsWith(CSL1("general_"))) { o = handleGeneralPages(fStack,p); } else { TQCString library = TQFile::encodeName(libraryName); KLibFactory *f = KLibLoader::self()->factory(library); if (!f) { #ifdef DEBUG DEBUGKPILOT << fname << ": No conduit library " << library.data() << " [" << library.size() << "]" << " (" << libraryName << ")" << " found." << endl; #endif fStack->raiseWidget(BROKEN_CONDUIT); warnNoLibrary(p); return; } dumpConduitInfo(KLibLoader::self()->library(library)); TQStringList a; a.append(CSL1("modal")); o = f->create(TQT_TQOBJECT(fStack), 0L, "ConduitConfigBase", a); if (!o) { #ifdef DEBUG DEBUGKPILOT << fname << ": Can't create ConduitConfigBase - must be old conduit." << endl; #endif KLibLoader::self()->unloadLibrary( library); fStack->raiseWidget(BROKEN_CONDUIT); warnNoLibrary(p); return; } } ConduitConfigBase *d = dynamic_cast(o); if (!d) { #ifdef DEBUG DEBUGKPILOT << fname << ": Can't cast to config base object." << endl; #endif fStack->raiseWidget(BROKEN_CONDUIT); warnNoLibrary(p); return; } // Remove the config widget from the stack before we can add the new one TQWidget *oldConfigWidget = fStack->widget( NEW_CONDUIT ); if ( oldConfigWidget ) { fStack->removeWidget( oldConfigWidget ); KPILOT_DELETE( oldConfigWidget ); } if (fStack->addWidget(d->widget(),NEW_CONDUIT)<0) { #ifdef DEBUG DEBUGKPILOT << fname << ": Can't add config widget to stack." << endl; #endif } else { d->load(); fStack->raiseWidget(NEW_CONDUIT); d->widget()->show(); fCurrentConfig=d; // make sure the changed signal is propagated to the KCM*Dialog // and the apply button is enabled correspondingly. connect(d, TQT_SIGNAL(changed(bool)), this, TQT_SIGNAL(changed(bool))); } } bool ConduitConfigWidget::release() { FUNCTIONSETUP; if (fCurrentConfig) { if (!fCurrentConfig->maybeSave()) return false; fStack->raiseWidget(0); delete fCurrentConfig; } if (fCurrentConduit) { KLibLoader::self()->unloadLibrary( TQFile::encodeName(fCurrentConduit->text(CONDUIT_LIBRARY))); } fCurrentConduit=0L; fCurrentConfig=0L; return true; } void ConduitConfigWidget::unselect() { fConduitList->setSelected( fCurrentConduit, true ); fConduitList->setCurrentItem( fCurrentConduit ); } void ConduitConfigWidget::selected(TQListViewItem *p) { FUNCTIONSETUP; #ifdef DEBUG DEBUGKPILOT << fname << ": " << ( p ? p->text(CONDUIT_NAME) : CSL1("None") ) << endl; #endif if (p!=fCurrentConduit) { if (!release()) { fConduitList->blockSignals(true); TQTimer::singleShot(1,this,TQT_SLOT(unselect())); return; } } fCurrentConduit=p; loadAndConfigure(p); // fStack->adjustSize(); #ifdef DEBUG DEBUGKPILOT << fname << ": New widget size " << fStack->size().width() << "x" << fStack->size().height() << endl; DEBUGKPILOT << fname << ": Current size " << size().width() << "x" << size().height() << endl; #endif emit sizeChanged(); #ifdef DEBUG DEBUGKPILOT << fname << ": New size " << size().width() << "x" << size().height() << endl; #endif // set the dialog title to the selected item TQListViewItem *pParent = p->parent(); TQString title; title = pParent ? pParent->text(CONDUIT_NAME) + CSL1(" - ") : TQString() ; title += p ? p->text(CONDUIT_NAME) : i18n("KPilot Setup"); fTitleText->setText(title); } void ConduitConfigWidget::configure() { loadAndConfigure(fConduitList->selectedItem()); } void ConduitConfigWidget::warnNoExec(const TQListViewItem * p) { FUNCTIONSETUP; TQString msg = i18n("No library could be " "found for the conduit %1. This means that the " "conduit was not installed properly.") .tqarg(p->text(CONDUIT_NAME)); #ifdef DEBUG DEBUGKPILOT << fname << ": No library for " << p->text(CONDUIT_NAME) << endl; #endif KMessageBox::error(this, msg, i18n("Conduit Error")); } void ConduitConfigWidget::warnNoLibrary(const TQListViewItem *p) { FUNCTIONSETUP; TQString msg = i18n("There was a problem loading the library " "for the conduit %1. This means that the " "conduit was not installed properly.") .tqarg(p->text(CONDUIT_NAME)); #ifdef DEBUG DEBUGKPILOT << fname << ": Can't load library for " << p->text(CONDUIT_NAME) << endl; #endif KMessageBox::error(this, msg, i18n("Conduit Error")); } void ConduitConfigWidget::save() { FUNCTIONSETUP; // Only new-style conduits and the general setup have changes that need to be commited // old-style conduits have their own config dlg which commits them itself if ( fStack->id( fStack->visibleWidget())==NEW_CONDUIT ) { if (fCurrentConfig) fCurrentConfig->commit(); } TQStringList activeConduits; TQListViewItemIterator it( fConduitList ); while ( it.current() ) { KPilotCheckListItem*p = dynamic_cast(it.current()); if ( p ) { p->setOriginalState( p->isOn() ); if ( p->isOn() ) activeConduits.append(p->text(CONDUIT_DESKTOP)); } ++it; } KPilotSettings::setInstalledConduits(activeConduits); KPilotSettings::self()->writeConfig(); } void ConduitConfigWidget::load() { FUNCTIONSETUP; KPilotSettings::self()->readConfig(); TQStringList potentiallyInstalled = KPilotSettings::installedConduits(); TQListViewItem*p = fConduitList->firstChild(); while (p) { TQListViewItem*q = p->firstChild(); while (q) { TQCheckListItem*qq=dynamic_cast(q); if (qq) { qq->setOn(! (potentiallyInstalled.findIndex(qq->text(CONDUIT_DESKTOP))<0) ); } q = q->nextSibling(); } p=p->nextSibling(); } // Only new-style conduits and the general setup have changes that need to be commited // old-style conduits have their own config dlg which commits them itself if ( fStack->id( fStack->visibleWidget())==NEW_CONDUIT ) { if (fCurrentConfig) fCurrentConfig->load(); } } void ConduitConfigWidget::conduitsChanged(TQListViewItem*item) { KPilotCheckListItem*i=dynamic_cast(item); if (i) { if (!i->isOriginalState()) emit changed(true); } } void ConduitConfigWidget::reopenItem(TQListViewItem *i) { i->setOpen(true); } void ConduitConfigWidget::configureWizard() { FUNCTIONSETUP; ConfigWizard wiz(this, "Wizard"); if (wiz.exec()) { KPilotSettings::self()->readConfig(); load(); } }