You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
digikam/digikam/libs/dialogs/imageguidedlg.cpp

598 lines
18 KiB

/* ============================================================
*
* 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 <caulier dot gilles at gmail dot com>
*
* 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 <tqvgroupbox.h>
#include <tqlabel.h>
#include <tqpushbutton.h>
#include <tqwhatsthis.h>
#include <tqtooltip.h>
#include <tqlayout.h>
#include <tqframe.h>
#include <tqtimer.h>
#include <tqspinbox.h>
#include <tqsplitter.h>
#include <tqhbox.h>
// KDE includes.
#include <kcursor.h>
#include <klocale.h>
#include <kaboutdata.h>
#include <khelpmenu.h>
#include <kiconloader.h>
#include <kapplication.h>
#include <kpopupmenu.h>
#include <kstandarddirs.h>
#include <kglobalsettings.h>
#include <kprogress.h>
#include <kcolorbutton.h>
#include <tdeconfig.h>
#include <kseparator.h>
// 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("<p>Reset all filter parameters to their default values.") );
setButtonWhatsThis ( User1, i18n("<p>Abort the current image rendering.") );
setButtonWhatsThis ( User3, i18n("<p>Load all filter parameters from settings text file.") );
setButtonWhatsThis ( User2, i18n("<p>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("<p>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("<p>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(Qt::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("<p>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("<p>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("<p>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, TQT_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, TQT_SLOT(readUserSettings()));
if (!d->tryAction)
{
connect(m_imagePreviewWidget, TQT_SIGNAL(signalResized()),
this, TQT_SLOT(slotResized()));
}
connect(d->guideColorBt, TQT_SIGNAL(changed(const TQColor &)),
m_imagePreviewWidget, TQT_SLOT(slotChangeGuideColor(const TQColor &)));
connect(d->guideSize, TQT_SIGNAL(valueChanged(int)),
m_imagePreviewWidget, TQT_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, TQT_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, TQT_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, TQT_SIGNAL(timeout()),
this, TQT_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