/* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2005-05-07 * Description : A threaded filter plugin dialog with a preview * image guide widget and a settings user area * * Copyright (C) 2005-2007 by Gilles Caulier * * 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, 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. * * ============================================================ */ // TQt includes. #include #include #include #include #include #include #include #include #include #include #include // KDE includes. #include #include #include #include #include #include #include #include #include #include #include #include #include // Local includes. #include "ddebug.h" #include "sidebar.h" #include "dimgthreadedfilter.h" #include "dimginterface.h" #include "imageguidedlg.h" #include "imageguidedlg.moc" namespace Digikam { class ImageGuideDlgPriv { public: enum RunningMode { NoneRendering=0, PreviewRendering, FinalRendering }; ImageGuideDlgPriv() { tryAction = false; progress = true; currentRenderingMode = NoneRendering; parent = 0; settings = 0; timer = 0; aboutData = 0; guideColorBt = 0; progressBar = 0; guideSize = 0; mainLayout = 0; settingsLayout = 0; hbox = 0; settingsSideBar = 0; splitter = 0; } bool tryAction; bool progress; int currentRenderingMode; TQWidget *parent; TQWidget *settings; TQTimer *timer; TQString name; TQGridLayout *mainLayout; TQGridLayout *settingsLayout; TQSpinBox *guideSize; TQHBox *hbox; TQSplitter *splitter; KProgress *progressBar; KColorButton *guideColorBt; TDEAboutData *aboutData; Sidebar *settingsSideBar; }; ImageGuideDlg::ImageGuideDlg(TQWidget* parent, TQString title, TQString name, bool loadFileSettings, bool progress, bool guideVisible, int guideMode, TQFrame* bannerFrame, bool prevModeOptions, bool useImageSelection, bool tryAction) : KDialogBase(Plain, 0, Help|Default|User1|User2|User3|Try|Ok|Cancel, Ok, parent, 0, true, true, i18n("&Abort"), i18n("&Save As..."), i18n("&Load...")) { kapp->setOverrideCursor( KCursor::waitCursor() ); setCaption(DImgInterface::defaultInterface()->getImageFileName() + TQString(" - ") + title); d = new ImageGuideDlgPriv; d->parent = parent; d->name = name; d->progress = progress; d->tryAction = tryAction; m_threadedFilter = 0; TQString whatsThis; setButtonWhatsThis ( Default, i18n("

Reset all filter parameters to their default values.") ); setButtonWhatsThis ( User1, i18n("

Abort the current image rendering.") ); setButtonWhatsThis ( User3, i18n("

Load all filter parameters from settings text file.") ); setButtonWhatsThis ( User2, i18n("

Save all filter parameters to settings text file.") ); showButton(User2, loadFileSettings); showButton(User3, loadFileSettings); showButton(Try, tryAction); resize(configDialogSize(name + TQString(" Tool Dialog"))); // ------------------------------------------------------------- d->mainLayout = new TQGridLayout( plainPage(), 2, 1); if (bannerFrame) { bannerFrame->reparent( plainPage(), TQPoint(0, 0) ); d->mainLayout->addMultiCellWidget(bannerFrame, 0, 0, 0, 1); } // ------------------------------------------------------------- TQString desc; if (guideVisible) desc = i18n("

This is the the image filter effect preview. " "If you move the mouse cursor on this area, " "a vertical and horizontal dashed line will be draw " "to guide you in adjusting the filter settings. " "Press the left mouse button to freeze the dashed " "line's position."); else desc = i18n("

This is the image filter effect preview."); d->hbox = new TQHBox(plainPage()); d->splitter = new TQSplitter(d->hbox); m_imagePreviewWidget = new ImageWidget(d->name, d->splitter, desc, prevModeOptions, guideMode, guideVisible, useImageSelection); d->splitter->setFrameStyle( TQFrame::NoFrame ); d->splitter->setFrameShadow( TQFrame::Plain ); d->splitter->setFrameShape( TQFrame::NoFrame ); d->splitter->setOpaqueResize(false); TQSizePolicy rightSzPolicy(TQSizePolicy::Preferred, TQSizePolicy::Expanding, 2, 1); m_imagePreviewWidget->setSizePolicy(rightSzPolicy); TQString sbName(d->name + TQString(" Image Plugin Sidebar")); d->settingsSideBar = new Sidebar(d->hbox, sbName.ascii(), Sidebar::Right); d->settingsSideBar->setSplitter(d->splitter); d->mainLayout->addMultiCellWidget(d->hbox, 1, 2, 0, 1); d->mainLayout->setColStretch(0, 10); d->mainLayout->setRowStretch(2, 10); // ------------------------------------------------------------- d->settings = new TQWidget(plainPage()); d->settingsLayout = new TQGridLayout( d->settings, 1, 0); TQVBoxLayout *vLayout = new TQVBoxLayout( spacingHint() ); // ------------------------------------------------------------- TQWidget *gboxGuideSettings = new TQWidget(d->settings); TQGridLayout* grid = new TQGridLayout( gboxGuideSettings, 2, 2, marginHint(), spacingHint()); KSeparator *line = new KSeparator(TQt::Horizontal, gboxGuideSettings); grid->addMultiCellWidget(line, 0, 0, 0, 2); TQLabel *label5 = new TQLabel(i18n("Guide color:"), gboxGuideSettings); d->guideColorBt = new KColorButton( TQColor( TQt::red ), gboxGuideSettings ); TQWhatsThis::add( d->guideColorBt, i18n("

Set here the color used to draw guides dashed-lines.")); grid->addMultiCellWidget(label5, 1, 1, 0, 0); grid->addMultiCellWidget(d->guideColorBt, 1, 1, 2, 2); TQLabel *label6 = new TQLabel(i18n("Guide width:"), gboxGuideSettings); d->guideSize = new TQSpinBox( 1, 5, 1, gboxGuideSettings); TQWhatsThis::add( d->guideSize, i18n("

Set here the width in pixels used to draw guides dashed-lines.")); grid->addMultiCellWidget(label6, 2, 2, 0, 0); grid->addMultiCellWidget(d->guideSize, 2, 2, 2, 2); grid->setColStretch(1, 10); if (guideVisible) gboxGuideSettings->show(); else gboxGuideSettings->hide(); vLayout->addWidget(gboxGuideSettings); TQHBox *hbox = new TQHBox(d->settings); TQLabel *space1 = new TQLabel(hbox); space1->setFixedWidth(spacingHint()); d->progressBar = new KProgress(100, hbox); d->progressBar->setMaximumHeight( fontMetrics().height() ); TQWhatsThis::add(d->progressBar ,i18n("

This is the percentage of the task which has been completed up to this point.")); d->progressBar->setValue(0); setProgressVisible(false); TQLabel *space2 = new TQLabel(hbox); space2->setFixedWidth(spacingHint()); vLayout->addWidget(hbox); vLayout->addStretch(10); d->settingsLayout->addMultiCellLayout(vLayout, 1, 1, 0, 0); d->settingsSideBar->appendTab(d->settings, SmallIcon("configure"), i18n("Settings")); d->settingsSideBar->loadViewState(); // Reading splitter sizes here prevent flicker effect in dialog. TDEConfig *config = kapp->config(); config->setGroup(d->name + TQString(" Tool Dialog")); if(config->hasKey("SplitterSizes")) d->splitter->setSizes(config->readIntListEntry("SplitterSizes")); // ------------------------------------------------------------- TQTimer::singleShot(0, this, TQ_SLOT(slotInit())); kapp->restoreOverrideCursor(); } ImageGuideDlg::~ImageGuideDlg() { if (d->timer) delete d->timer; if (m_threadedFilter) delete m_threadedFilter; if (d->aboutData) delete d->aboutData; delete d->settingsSideBar; delete d; } void ImageGuideDlg::readSettings(void) { TQColor defaultGuideColor(TQt::red); TDEConfig *config = kapp->config(); config->setGroup(d->name + TQString(" Tool Dialog")); d->guideColorBt->setColor(config->readColorEntry("Guide Color", &defaultGuideColor)); d->guideSize->setValue(config->readNumEntry("Guide Width", 1)); m_imagePreviewWidget->slotChangeGuideSize(d->guideSize->value()); m_imagePreviewWidget->slotChangeGuideColor(d->guideColorBt->color()); } void ImageGuideDlg::writeSettings(void) { TDEConfig *config = kapp->config(); config->setGroup(d->name + TQString(" Tool Dialog")); config->writeEntry( "Guide Color", d->guideColorBt->color() ); config->writeEntry( "Guide Width", d->guideSize->value() ); config->writeEntry( "SplitterSizes", d->splitter->sizes() ); config->sync(); saveDialogSize(d->name + TQString(" Tool Dialog")); } void ImageGuideDlg::slotInit() { readSettings(); // Reset values to defaults. TQTimer::singleShot(0, this, TQ_SLOT(readUserSettings())); if (!d->tryAction) { connect(m_imagePreviewWidget, TQ_SIGNAL(signalResized()), this, TQ_SLOT(slotResized())); } connect(d->guideColorBt, TQ_SIGNAL(changed(const TQColor &)), m_imagePreviewWidget, TQ_SLOT(slotChangeGuideColor(const TQColor &))); connect(d->guideSize, TQ_SIGNAL(valueChanged(int)), m_imagePreviewWidget, TQ_SLOT(slotChangeGuideSize(int))); } void ImageGuideDlg::setUserAreaWidget(TQWidget *w) { w->reparent( d->settings, TQPoint(0, 0) ); TQVBoxLayout *vLayout = new TQVBoxLayout( spacingHint() ); vLayout->addWidget(w); d->settingsLayout->addMultiCellLayout(vLayout, 0, 0, 0, 0); } void ImageGuideDlg::setAboutData(TDEAboutData *about) { d->aboutData = about; TQPushButton *helpButton = actionButton( Help ); KHelpMenu* helpMenu = new KHelpMenu(this, d->aboutData, false); helpMenu->menu()->removeItemAt(0); helpMenu->menu()->insertItem(i18n("digiKam Handbook"), this, TQ_SLOT(slotHelp()), 0, -1, 0); helpButton->setPopup( helpMenu->menu() ); } void ImageGuideDlg::setProgressVisible(bool v) { if (v) d->progressBar->show(); else d->progressBar->hide(); } void ImageGuideDlg::abortPreview() { d->currentRenderingMode = ImageGuideDlgPriv::NoneRendering; d->progressBar->setValue(0); setProgressVisible(false); enableButton(Ok, true); enableButton(User1, false); enableButton(User2, true); enableButton(User3, true); enableButton(Try, true); enableButton(Default, true); renderingFinished(); } void ImageGuideDlg::slotTry() { slotEffect(); } void ImageGuideDlg::slotResized(void) { if (d->currentRenderingMode == ImageGuideDlgPriv::FinalRendering) { m_imagePreviewWidget->update(); return; } else if (d->currentRenderingMode == ImageGuideDlgPriv::PreviewRendering) { if (m_threadedFilter) m_threadedFilter->stopComputation(); } TQTimer::singleShot(0, this, TQ_SLOT(slotEffect())); } void ImageGuideDlg::slotUser1() { if (d->currentRenderingMode != ImageGuideDlgPriv::NoneRendering) if (m_threadedFilter) m_threadedFilter->stopComputation(); } void ImageGuideDlg::slotDefault() { resetValues(); slotEffect(); } void ImageGuideDlg::slotCancel() { if (d->currentRenderingMode != ImageGuideDlgPriv::NoneRendering) { if (m_threadedFilter) m_threadedFilter->stopComputation(); kapp->restoreOverrideCursor(); } writeSettings(); done(Cancel); } void ImageGuideDlg::closeEvent(TQCloseEvent *e) { if (d->currentRenderingMode != ImageGuideDlgPriv::NoneRendering) { if (m_threadedFilter) m_threadedFilter->stopComputation(); kapp->restoreOverrideCursor(); } writeSettings(); e->accept(); } void ImageGuideDlg::slotHelp() { // If setAboutData() is called by plugin, well DigikamImagePlugins help is lauched, // else digiKam help. In this case, setHelp() method must be used to set anchor and handbook name. if (d->aboutData) TDEApplication::kApplication()->invokeHelp(d->name, "digikam"); else KDialogBase::slotHelp(); } void ImageGuideDlg::slotTimer() { if (d->timer) { d->timer->stop(); delete d->timer; } d->timer = new TQTimer( this ); connect( d->timer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotEffect()) ); d->timer->start(500, true); } void ImageGuideDlg::slotEffect() { // Computation already in process. if (d->currentRenderingMode != ImageGuideDlgPriv::NoneRendering) return; d->currentRenderingMode = ImageGuideDlgPriv::PreviewRendering; DDebug() << "Preview " << d->name << " started..." << endl; enableButton(Ok, false); enableButton(User1, true); enableButton(User2, false); enableButton(User3, false); enableButton(Default, false); enableButton(Try, false); d->progressBar->setValue(0); if (d->progress) setProgressVisible(true); if (m_threadedFilter) { delete m_threadedFilter; m_threadedFilter = 0; } prepareEffect(); } void ImageGuideDlg::slotOk() { d->currentRenderingMode = ImageGuideDlgPriv::FinalRendering; DDebug() << "Final " << d->name << " started..." << endl; writeSettings(); writeUserSettings(); enableButton(Ok, false); enableButton(User1, false); enableButton(User2, false); enableButton(User3, false); enableButton(Default, false); enableButton(Try, false); kapp->setOverrideCursor( KCursor::waitCursor() ); d->progressBar->setValue(0); if (m_threadedFilter) { delete m_threadedFilter; m_threadedFilter = 0; } prepareFinal(); } void ImageGuideDlg::customEvent(TQCustomEvent *event) { if (!event) return; DImgThreadedFilter::EventData *ed = (DImgThreadedFilter::EventData*) event->data(); if (!ed) return; if (ed->starting) // Computation in progress ! { d->progressBar->setValue(ed->progress); } else { if (ed->success) // Computation Completed ! { switch (d->currentRenderingMode) { case ImageGuideDlgPriv::PreviewRendering: { DDebug() << "Preview " << d->name << " completed..." << endl; putPreviewData(); abortPreview(); break; } case ImageGuideDlgPriv::FinalRendering: { DDebug() << "Final" << d->name << " completed..." << endl; putFinalData(); kapp->restoreOverrideCursor(); accept(); break; } } } else // Computation Failed ! { switch (d->currentRenderingMode) { case ImageGuideDlgPriv::PreviewRendering: { DDebug() << "Preview " << d->name << " failed..." << endl; // abortPreview() must be call here for set progress bar to 0 properly. abortPreview(); break; } case ImageGuideDlgPriv::FinalRendering: break; } } } delete ed; } // Backport KDialog::keyPressEvent() implementation from KDELibs to ignore Enter/Return Key events // to prevent any conflicts between dialog keys events and SpinBox keys events. void ImageGuideDlg::keyPressEvent(TQKeyEvent *e) { if ( e->state() == 0 ) { switch ( e->key() ) { case Key_Escape: e->accept(); reject(); break; case Key_Enter: case Key_Return: e->ignore(); break; default: e->ignore(); return; } } else { // accept the dialog when Ctrl-Return is pressed if ( e->state() == ControlButton && (e->key() == Key_Return || e->key() == Key_Enter) ) { e->accept(); accept(); } else { e->ignore(); } } } } // NameSpace Digikam