1
// vim: set tabstop=4 shiftwidth=4 noexpandtab:
3
Gwenview - A simple image viewer for KDE
4
Copyright 2000-2004 Aur�ien G�eau
6
This program is free software; you can redistribute it and/or
7
modify it under the terms of the GNU General Public License
8
as published by the Free Software Foundation; either version 2
9
of the License, or (at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
#include <qdockarea.h>
26
#include <qtabwidget.h>
29
#include <kaboutdata.h>
32
#include <kapplication.h>
33
#include <kbookmarkmanager.h>
34
#include <kbookmarkmenu.h>
35
#include <kcmdlineargs.h>
36
#include <kcombobox.h>
39
#include <kdeversion.h>
40
#include <kdockwidget.h>
41
#include <kedittoolbar.h>
42
#include <kfiledialog.h>
44
#include <khelpmenu.h>
45
#include <kiconloader.h>
47
#include <kio/netaccess.h>
48
#include <kkeydialog.h>
49
#include <klargefile.h>
50
#include <klistview.h>
53
#include <kmessagebox.h>
54
#include <kpopupmenu.h>
55
#include <kstandarddirs.h>
56
#include <kstatusbar.h>
57
#include <kstdaccel.h>
58
#include <kstdaction.h>
59
#include <ktoolbarbutton.h>
60
#include <kurlcompletion.h>
61
#include <kurlpixmapprovider.h>
62
#include <kurlrequesterdlg.h>
68
#include <libkipi/plugin.h>
69
#include <libkipi/pluginloader.h>
73
#include "bookmarkowner.h"
74
#include "bookmarkviewcontroller.h"
75
#include "configdialog.h"
79
#include "truncatedtextlabel.h"
81
#include "gvcore/fileoperation.h"
82
#include "gvcore/archive.h"
83
#include "gvcore/batchmanipulator.h"
84
#include "gvcore/captionformatter.h"
85
#include "gvcore/document.h"
86
#include "gvcore/externaltooldialog.h"
87
#include "gvcore/fileviewbase.h"
88
#include "gvcore/fileviewstack.h"
89
#include "gvcore/imageview.h"
90
#include "gvcore/slideshow.h"
91
#include "gvcore/slideshowdialog.h"
92
#include "gvcore/printdialog.h"
93
#include "gvcore/cache.h"
94
#include "gvcore/thumbnailloadjob.h"
99
#include "gvcore/kipiinterface.h"
104
#include "mainwindow.moc"
107
const char CONFIG_DOCK_GROUP[]="dock";
108
const char CONFIG_MAINWINDOW_GROUP[]="main window";
109
const char CONFIG_FILEWIDGET_GROUP[]="file widget";
110
const char CONFIG_DIRWIDGET_GROUP[]="dir widget";
111
const char CONFIG_PIXMAPWIDGET_GROUP[]="pixmap widget";
112
const char CONFIG_FILEOPERATION_GROUP[]="file operations";
113
const char CONFIG_SLIDESHOW_GROUP[]="slide show";
114
const char CONFIG_CACHE_GROUP[]="cache";
115
const char CONFIG_THUMBNAILLOADJOB_GROUP[]="thumbnail loading";
117
const char CONFIG_BUSYPTR_IN_FS[]="busy ptr in full screen";
118
const char CONFIG_SHOW_LOCATION_TOOLBAR[]="show address bar";
119
const char CONFIG_AUTO_DELETE_THUMBNAIL_CACHE[]="Delete Thumbnail Cache whe exit";
120
const char CONFIG_GWENVIEW_DOCK_VERSION[]="Gwenview version";
122
const char CONFIG_SESSION_URL[] = "url";
124
// This version is here to avoid configuration migration troubles when changes
125
// are made to the dock behavior
126
const int GWENVIEW_DOCK_VERSION=2;
128
// The timeout before an hint in the statusbar disappear (in msec)
129
const int HINT_TIMEOUT=10000;
131
// Time before we try to load the KIPI plugins (in msec)
132
const int LOAD_PLUGIN_DELAY=1000;
136
#define LOG(x) kdDebug() << k_funcinfo << x << endl
141
enum { StackIDBrowse, StackIDView };
144
// This function is used in the ctor to find out whether to start in viewing
145
// or browsing mode if URL is passed on the command line.
146
static bool urlIsDirectory(QWidget* parent, const KURL& url) {
147
if( url.filename( false ).isEmpty()) return true; // file:/somewhere/<nothing here>
148
// Do direct stat instead of using KIO if the file is local (faster)
149
if( url.isLocalFile()
150
&& !KIO::probably_slow_mounted( url.path())) {
151
KDE_struct_stat buff;
152
if ( KDE_stat( QFile::encodeName(url.path()), &buff ) == 0 ) {
153
return S_ISDIR( buff.st_mode );
157
if( KIO::NetAccess::stat( url, entry, parent)) {
158
KIO::UDSEntry::ConstIterator it;
159
for(it=entry.begin();it!=entry.end();++it) {
160
if ((*it).m_uds==KIO::UDS_FILE_TYPE) {
161
return S_ISDIR( (*it).m_long );
169
MainWindow::MainWindow()
171
, mLoadingCursor(false)
176
FileOperation::readConfig(KGlobal::config(),CONFIG_FILEOPERATION_GROUP);
177
readConfig(KGlobal::config(),CONFIG_MAINWINDOW_GROUP);
180
mDocument=new Document(this);
181
mHistory=new History(actionCollection());
185
createLocationToolBar();
186
createObjectInteractions();
188
setStandardToolBarMenuEnabled(true);
189
createGUI("gwenviewui.rc", false);
192
mWindowListActions.setAutoDelete(true);
193
updateWindowActions();
194
applyMainWindowSettings();
196
if( !kapp->isSessionRestored()) {
198
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
200
if (args->count()==0) {
202
url.setPath( QDir::currentDirPath() );
203
mFileViewStack->setDirURL(url);
205
bool fullscreen=args->isSet("f");
206
if (fullscreen) mToggleFullScreen->activate();
207
KURL url=args->url(0);
209
if( urlIsDirectory(this, url)) {
210
mFileViewStack->setDirURL(url);
212
if (!fullscreen) mToggleBrowse->activate();
219
if (mToggleBrowse->isChecked()) {
220
mFileViewStack->setFocus();
222
mImageView->setFocus();
225
QTimer::singleShot(LOAD_PLUGIN_DELAY, this, SLOT(loadPlugins()) );
229
bool MainWindow::queryClose() {
230
mDocument->saveBeforeClosing();
232
KConfig* config=KGlobal::config();
233
FileOperation::writeConfig(config, CONFIG_FILEOPERATION_GROUP);
234
mImageView->writeConfig(config, CONFIG_PIXMAPWIDGET_GROUP);
235
mFileViewStack->writeConfig(config, CONFIG_FILEWIDGET_GROUP);
236
mDirView->writeConfig(config, CONFIG_DIRWIDGET_GROUP);
237
mSlideShow->writeConfig(config, CONFIG_SLIDESHOW_GROUP);
238
ThumbnailLoadJob::writeConfig(config, CONFIG_THUMBNAILLOADJOB_GROUP);
240
// Don't store dock layout if only the image dock is visible. This avoid
241
// saving layout when in "fullscreen" or "image only" mode.
242
if (mFileViewStack->isVisible() || mDirView->isVisible()) {
243
mDockArea->writeDockConfig(config,CONFIG_DOCK_GROUP);
245
writeConfig(config,CONFIG_MAINWINDOW_GROUP);
247
if (mAutoDeleteThumbnailCache) {
248
QString dir=ThumbnailLoadJob::thumbnailBaseDir();
250
if (QFile::exists(dir)) {
253
KIO::NetAccess::del(url, this);
257
if (!mToggleFullScreen->isChecked()) {
258
saveMainWindowSettings(KGlobal::config(), "MainWindow");
263
void MainWindow::saveProperties( KConfig* cfg ) {
264
cfg->writeEntry( CONFIG_SESSION_URL, mFileViewStack->url().url());
267
void MainWindow::readProperties( KConfig* cfg ) {
268
KURL url(cfg->readEntry(CONFIG_SESSION_URL));
269
if( urlIsDirectory(this, url)) {
270
mFileViewStack->setDirURL(url);
276
//-----------------------------------------------------------------------
280
//-----------------------------------------------------------------------
281
void MainWindow::openURL(const KURL& url) {
282
mDocument->setURL(url);
283
mFileViewStack->setDirURL(url.upURL());
284
mFileViewStack->setFileNameToSelect(url.filename());
288
void MainWindow::slotDirURLChanged(const KURL& dirURL) {
289
LOG(dirURL.prettyURL(0,KURL::StripFileProtocol));
291
if (dirURL.path()!="/") {
292
mGoUp->setEnabled(true);
293
QPopupMenu *upPopup = mGoUp->popupMenu();
296
KURL url = dirURL.upURL();
297
for (; url.hasPath() && pos<10; url=url.upURL(), ++pos) {
298
upPopup->insertItem(url.url());
299
if (url.path()=="/") break;
302
mGoUp->setEnabled(false);
306
updateImageActions();
310
void MainWindow::updateLocationURL() {
313
if (mToggleBrowse->isChecked()) {
314
url=mFileViewStack->dirURL();
315
if (!url.isValid()) {
316
url=mDocument->url();
319
url=mDocument->url();
321
LOG(url.prettyURL());
322
#if KDE_IS_VERSION( 3, 4, 0 )
323
mURLEdit->setEditText(url.pathOrURL());
324
mURLEdit->addToHistory(url.pathOrURL());
326
mURLEdit->setEditText(url.prettyURL(0,KURL::StripFileProtocol));
327
mURLEdit->addToHistory(url.prettyURL(0,KURL::StripFileProtocol));
331
void MainWindow::goUp() {
332
goUpTo(mGoUp->popupMenu()->idAt(0));
335
void MainWindow::goUpTo(int id) {
336
KPopupMenu* menu=mGoUp->popupMenu();
337
KURL url(menu->text(id));
339
int index=menu->indexOf(id);
341
childURL=KURL(menu->text(menu->idAt(index-1)));
343
childURL=mDocument->dirURL();
345
mFileViewStack->setDirURL(url);
346
mFileViewStack->setFileNameToSelect(childURL.fileName());
350
//-----------------------------------------------------------------------
354
//-----------------------------------------------------------------------
355
void MainWindow::goHome() {
357
url.setPath( QDir::homeDirPath() );
358
mFileViewStack->setDirURL(url);
362
void MainWindow::renameFile() {
363
if (mFileViewStack->isVisible()) {
364
mFileViewStack->renameFile();
366
mImageView->renameFile();
371
void MainWindow::copyFiles() {
372
if (mFileViewStack->isVisible()) {
373
mFileViewStack->copyFiles();
375
mImageView->copyFile();
380
void MainWindow::moveFiles() {
381
if (mFileViewStack->isVisible()) {
382
mFileViewStack->moveFiles();
384
mImageView->moveFile();
389
void MainWindow::deleteFiles() {
390
if (mFileViewStack->isVisible()) {
391
mFileViewStack->deleteFiles();
393
mImageView->deleteFile();
398
void MainWindow::showFileProperties() {
399
if (mFileViewStack->isVisible()) {
400
mFileViewStack->showFileProperties();
402
mImageView->showFileProperties();
407
void MainWindow::rotateLeft() {
408
modifyImage(ImageUtils::ROT_270);
411
void MainWindow::rotateRight() {
412
modifyImage(ImageUtils::ROT_90);
415
void MainWindow::mirror() {
416
modifyImage(ImageUtils::HFLIP);
419
void MainWindow::flip() {
420
modifyImage(ImageUtils::VFLIP);
423
void MainWindow::modifyImage(ImageUtils::Orientation orientation) {
424
const KURL::List& urls=mFileViewStack->selectedImageURLs();
425
if (mFileViewStack->isVisible() && urls.size()>1) {
426
BatchManipulator manipulator(this, urls, orientation);
427
connect(&manipulator, SIGNAL(imageModified(const KURL&)),
428
mFileViewStack, SLOT(updateThumbnail(const KURL&)) );
430
if (urls.find(mDocument->url())!=urls.end()) {
434
mDocument->transform(orientation);
438
void MainWindow::showFileDialog() {
439
KURL url=KFileDialog::getOpenURL();
440
if (!url.isValid()) return;
446
void MainWindow::printFile() {
449
printer.setDocName(mDocument->filename());
450
const KAboutData* pAbout = KApplication::kApplication()->aboutData();
451
QString nm = pAbout->appName();
453
nm += pAbout->version();
454
printer.setCreator( nm );
456
KPrinter::addDialogPage( new PrintDialogPage( mDocument, this, " page"));
458
if (printer.setup(this, QString::null, true)) {
459
mDocument->print(&printer);
464
//-----------------------------------------------------------------------
468
//-----------------------------------------------------------------------
469
void MainWindow::slotImageLoading() {
470
if (mShowBusyPtrInFullScreen || !mToggleFullScreen->isChecked()) {
471
if( !mLoadingCursor ) {
472
kapp->setOverrideCursor(KCursor::workingCursor());
474
mLoadingCursor = true;
479
void MainWindow::slotImageLoaded() {
481
kapp->restoreOverrideCursor();
482
mLoadingCursor = false;
484
updateImageActions();
489
void MainWindow::hideToolBars() {
490
QPtrListIterator<KToolBar> it=toolBarIterator();
493
for(;it.current()!=0L; ++it) {
504
void MainWindow::showToolBars() {
505
QPtrListIterator<KToolBar> it=toolBarIterator();
509
for(;it.current()!=0L; ++it) {
520
void MainWindow::toggleFullScreen() {
521
if (mToggleFullScreen->isChecked()) {
522
saveMainWindowSettings(KGlobal::config(), "MainWindow");
529
* If the toolbar is docked we hide the DockArea to avoid
530
* having a one pixel band remaining
531
* For the same reason, we hide all the empty DockAreas
533
* NOTE: This does not work really well if the toolbar is in
534
* the left or right dock area.
537
if (leftDock()->isEmpty()) leftDock()->hide();
538
if (rightDock()->isEmpty()) rightDock()->hide();
539
if (topDock()->isEmpty()) topDock()->hide();
540
if (bottomDock()->isEmpty()) bottomDock()->hide();
542
if (mToggleBrowse->isChecked()) {
543
mImageView->reparent(mViewModeWidget, QPoint(0,0));
544
mCentralStack->raiseWidget(StackIDView);
546
mImageView->setFullScreen(true);
547
mImageView->setFocus();
549
// Stop the slideshow if it's running, harmless if it does not
552
// Make sure the file view points to the right URL, it might not be the
553
// case if we are getting out of a slideshow
554
mFileViewStack->setDirURL(mDocument->url().upURL());
555
mFileViewStack->setFileNameToSelect(mDocument->url().fileName());
564
bottomDock()->show();
567
mImageView->setFullScreen(false);
569
if (mToggleBrowse->isChecked()) {
570
mPixmapDock->setWidget(mImageView);
571
mCentralStack->raiseWidget(StackIDBrowse);
573
mFileViewStack->setFocus();
578
void MainWindow::startSlideShow() {
580
KFileItemListIterator it( *mFileViewStack->currentFileView()->items() );
581
for ( ; it.current(); ++it ) {
582
KFileItem* item=it.current();
583
if (!item->isDir() && !Archive::fileItemIsArchive(item)) {
584
list.append(item->url());
587
if (list.count()==0) {
591
SlideShowDialog dialog(this,mSlideShow);
592
if (!dialog.exec()) return;
594
if (!mToggleFullScreen->isChecked()) {
595
mToggleFullScreen->activate();
597
mSlideShow->start(list);
601
void MainWindow::showConfigDialog() {
602
ConfigDialog dialog(this);
607
void MainWindow::showExternalToolDialog() {
608
ExternalToolDialog* dialog=new ExternalToolDialog(this);
613
void MainWindow::showKeyDialog() {
614
KKeyDialog dialog(true, this);
615
dialog.insert(actionCollection());
617
KIPI::PluginLoader::PluginList pluginList=mPluginLoader->pluginList();
618
KIPI::PluginLoader::PluginList::ConstIterator it(pluginList.begin());
619
KIPI::PluginLoader::PluginList::ConstIterator itEnd(pluginList.end());
620
for( ; it!=itEnd; ++it ) {
621
KIPI::Plugin* plugin=(*it)->plugin();
623
dialog.insert(plugin->actionCollection(), (*it)->name());
627
dialog.configure(true);
631
void MainWindow::showToolBarDialog() {
632
saveMainWindowSettings(KGlobal::config(), "MainWindow");
633
KEditToolbar dlg(actionCollection());
634
connect(&dlg,SIGNAL(newToolbarConfig()),this,SLOT(applyMainWindowSettings()));
640
void MainWindow::applyMainWindowSettings() {
641
KMainWindow::applyMainWindowSettings(KGlobal::config(), "MainWindow");
646
void MainWindow::escapePressed() {
647
if (mToggleFullScreen->isChecked()) {
648
mToggleFullScreen->activate();
653
void MainWindow::slotDirRenamed(const KURL& oldURL, const KURL& newURL) {
654
LOG(oldURL.prettyURL(0,KURL::StripFileProtocol) << " to " << newURL.prettyURL(0,KURL::StripFileProtocol));
656
KURL url(mFileViewStack->dirURL());
657
if (!oldURL.isParentOf(url) ) {
658
LOG(oldURL.prettyURL() << " is not a parent of " << url.prettyURL());
662
QString oldPath=oldURL.path();
663
LOG("current path: " << url.path() );
664
QString path=newURL.path() + url.path().mid(oldPath.length());
665
LOG("new path: " << path);
667
mFileViewStack->setDirURL(url);
671
void MainWindow::slotGo() {
672
KURL url(mURLEditCompletion->replacedPath(mURLEdit->currentText()));
673
LOG(url.prettyURL());
674
if( urlIsDirectory(this, url)) {
675
LOG(" '-> is a directory");
676
mFileViewStack->setDirURL(url);
678
LOG(" '-> is not a directory");
681
mFileViewStack->setFocus();
684
void MainWindow::slotShownFileItemRefreshed(const KFileItem*) {
690
void MainWindow::slotToggleCentralStack() {
692
if (mToggleBrowse->isChecked()) {
693
mPixmapDock->setWidget(mImageView);
694
mCentralStack->raiseWidget(StackIDBrowse);
695
mFileViewStack->setSilentMode( false );
696
// force re-reading the directory to show the error
697
if( mFileViewStack->lastURLError()) mFileViewStack->retryURL();
699
mImageView->reparent(mViewModeWidget, QPoint(0,0));
700
mCentralStack->raiseWidget(StackIDView);
701
mFileViewStack->setSilentMode( true );
704
// Make sure the window list actions are disabled if we are in view mode,
705
// otherwise weird things happens when we go back to browse mode
706
QPtrListIterator<KAction> it(mWindowListActions);
707
for (;it.current(); ++it) {
708
it.current()->setEnabled(mToggleBrowse->isChecked());
710
updateImageActions();
715
void MainWindow::resetDockWidgets() {
716
mFolderDock->undock();
717
mBookmarkDock->undock();
718
mPixmapDock->undock();
721
mFolderDock->manualDock(mFileDock, KDockWidget::DockLeft, 4000);
722
mPixmapDock->manualDock(mFolderDock, KDockWidget::DockBottom, 3734);
723
mMetaDock->manualDock(mPixmapDock, KDockWidget::DockBottom, 8560);
724
mBookmarkDock->manualDock(mFolderDock, KDockWidget::DockCenter, 0);
729
* Display a hint as a temporary message in the status bar
731
void MainWindow::showHint(const QString& hint) {
732
mSBHintLabel->setText(hint);
734
mSBHintLabel->show();
735
mHintTimer->start(HINT_TIMEOUT, true);
739
//-----------------------------------------------------------------------
743
//-----------------------------------------------------------------------
744
void MainWindow::updateStatusInfo() {
745
int pos=mFileViewStack->shownFilePosition();
746
uint count=mFileViewStack->fileCount();
747
QString filename=mDocument->filename();
750
txt=i18n("No Images");
752
txt=i18n("%1/%2 - %3 %4x%5 @ %6%")
756
.arg(mDocument->width())
757
.arg(mDocument->height())
758
.arg(int(mImageView->zoom()*100) );
760
mSBDetailLabel->setText(txt);
761
setCaption(filename);
765
void MainWindow::updateImageActions() {
766
bool imageActionsEnabled = !mDocument->isNull();
768
mStartSlideShow->setEnabled(imageActionsEnabled);
769
mRotateLeft->setEnabled(imageActionsEnabled);
770
mRotateRight->setEnabled(imageActionsEnabled);
771
mMirror->setEnabled(imageActionsEnabled);
772
mFlip->setEnabled(imageActionsEnabled);
773
mSaveFile->setEnabled(imageActionsEnabled);
774
mSaveFileAs->setEnabled(imageActionsEnabled);
775
mFilePrint->setEnabled(imageActionsEnabled);
776
mReload->setEnabled(imageActionsEnabled);
778
bool fileActionsEnabled =
780
|| (mFileViewStack->isVisible() && mFileViewStack->selectionSize()>0);
782
mRenameFile->setEnabled(fileActionsEnabled);
783
mCopyFiles->setEnabled(fileActionsEnabled);
784
mMoveFiles->setEnabled(fileActionsEnabled);
785
mDeleteFiles->setEnabled(fileActionsEnabled);
786
mShowFileProperties->setEnabled(fileActionsEnabled);
791
* This method creates all the widgets. Interactions between them and with
792
* actions are created in createObjectInteractions
794
void MainWindow::createWidgets() {
795
KConfig* config=KGlobal::config();
797
mCentralStack=new QWidgetStack(this);
798
setCentralWidget(mCentralStack);
800
mDockArea=new KDockArea(mCentralStack);
801
mCentralStack->addWidget(mDockArea, StackIDBrowse);
802
mDockArea->manager()->setSplitterHighResolution(true);
803
mDockArea->manager()->setSplitterOpaqueResize(true);
805
mViewModeWidget=new QWidget(mCentralStack);
806
QVBoxLayout* layout=new QVBoxLayout(mViewModeWidget);
807
layout->setAutoAdd(true);
808
mCentralStack->addWidget(mViewModeWidget);
811
mSBDetailLabel=new QLabel("", statusBar());
813
mSBHintLabel=new TruncatedTextLabel(statusBar());
814
QFont font=mSBHintLabel->font();
815
font.setItalic(true);
816
mSBHintLabel->setFont(font);
818
statusBar()->addWidget(mSBDetailLabel, 0);
819
statusBar()->addWidget(mSBHintLabel, 1);
820
mHintTimer=new QTimer(this);
821
connect(mHintTimer, SIGNAL(timeout()),
822
mSBHintLabel, SLOT(clear()) );
825
mPixmapDock = mDockArea->createDockWidget("Image",SmallIcon("gwenview"),NULL,i18n("Image"));
826
mImageView=new ImageView(mPixmapDock,mDocument,actionCollection());
827
mPixmapDock->setWidget(mImageView);
828
connect(mImageView, SIGNAL(requestHintDisplay(const QString&)),
829
this, SLOT(showHint(const QString&)) );
832
mFolderDock = mDockArea->createDockWidget("Folders",SmallIcon("folder_open"),NULL,i18n("Folders"));
833
mDirView=new DirView(mFolderDock);
834
mFolderDock->setWidget(mDirView);
837
mBookmarkDock = mDockArea->createDockWidget("Bookmarks", SmallIcon("bookmark"),NULL,i18n("Bookmarks"));
838
QVBox* bmBox=new QVBox(mBookmarkDock);
839
mBookmarkView=new KListView(bmBox);
840
mBookmarkToolBar=new KToolBar(bmBox, "", true);
841
mBookmarkDock->setWidget(bmBox);
844
mFileDock = mDockArea->createDockWidget("Files",SmallIcon("image"),NULL,i18n("Files"));
845
QVBox* vbox=new QVBox(this);
846
mFileViewToolBar=new KToolBar(vbox, "", true);
847
mFileViewStack=new FileViewStack(vbox, actionCollection());
848
mFileDock->setWidget(vbox);
849
mFileDock->setEnableDocking(KDockWidget::DockNone);
850
mDockArea->setMainDockWidget(mFileDock);
852
// Meta info edit widget
853
mMetaDock = mDockArea->createDockWidget("File Attributes", SmallIcon("info"),NULL,
855
mMetaEdit = new MetaEdit(mMetaDock, mDocument);
856
mMetaDock->setWidget(mMetaEdit);
858
// Slide show controller (not really a widget)
859
mSlideShow=new SlideShow(mDocument);
860
connect( mSlideShow, SIGNAL( nextURL( const KURL& )), SLOT( openURL( const KURL& )));
862
// Default position on desktop
863
setGeometry(20,20,720,520);
865
// Default dock config
866
// (The "magic numbers" were found by adjusting the layout from within the
867
// app and looking at the result in the configuration file)
868
mFolderDock->manualDock(mFileDock, KDockWidget::DockLeft, 4000);
869
mPixmapDock->manualDock(mFolderDock, KDockWidget::DockBottom, 3734);
870
mMetaDock->manualDock(mPixmapDock, KDockWidget::DockBottom, 8560);
871
mBookmarkDock->manualDock(mFolderDock, KDockWidget::DockCenter, 0);
873
// Load dock config if up to date
874
if (config->hasGroup(CONFIG_DOCK_GROUP)) {
875
config->setGroup(CONFIG_DOCK_GROUP);
876
if (config->readNumEntry(CONFIG_GWENVIEW_DOCK_VERSION, 1)==GWENVIEW_DOCK_VERSION) {
877
mDockArea->readDockConfig(config,CONFIG_DOCK_GROUP);
879
KMessageBox::sorry(this, i18n(
880
"<qt><b>Configuration update</b><br>"
881
"Due to some changes in the dock behavior, your old dock configuration has been discarded. "
882
"Please adjust your docks again.</qt>")
884
// Store the default dock config and create the
885
// GWENVIEW_DOCK_VERSION entry
886
mDockArea->writeDockConfig(config,CONFIG_DOCK_GROUP);
887
config->writeEntry(CONFIG_GWENVIEW_DOCK_VERSION, GWENVIEW_DOCK_VERSION);
891
// There was no dock config, lets create the GWENVIEW_DOCK_VERSION entry
892
config->setGroup(CONFIG_DOCK_GROUP);
893
config->writeEntry(CONFIG_GWENVIEW_DOCK_VERSION, GWENVIEW_DOCK_VERSION);
898
mFileViewStack->readConfig(config,CONFIG_FILEWIDGET_GROUP);
899
mDirView->readConfig(config,CONFIG_DIRWIDGET_GROUP);
900
mImageView->readConfig(config,CONFIG_PIXMAPWIDGET_GROUP);
901
mSlideShow->readConfig(config,CONFIG_SLIDESHOW_GROUP);
902
ThumbnailLoadJob::readConfig(config,CONFIG_THUMBNAILLOADJOB_GROUP);
903
Cache::instance()->readConfig(config,CONFIG_CACHE_GROUP);
908
* This method creates all the actions Interactions between them and with
909
* widgets are created in createObjectInteractions
911
void MainWindow::createActions() {
913
mToggleBrowse=new KToggleAction(i18n("Browse"), "folder", CTRL + Key_Return, this, SLOT(slotToggleCentralStack()), actionCollection(), "toggle_browse");
914
mToggleBrowse->setChecked(true);
915
mToggleBrowse->setShortcut(CTRL + Key_Return);
918
KStdAction::open(this,SLOT(showFileDialog()),actionCollection() );
919
mSaveFile=KStdAction::save(mDocument,SLOT(save()),actionCollection() );
920
mSaveFileAs=KStdAction::saveAs(mDocument,SLOT(saveAs()),actionCollection() );
921
mFilePrint = KStdAction::print(this, SLOT(printFile()), actionCollection());
922
mRenameFile=new KAction(i18n("&Rename..."),Key_F2,this,SLOT(renameFile()),actionCollection(),"file_rename");
923
mCopyFiles=new KAction(i18n("&Copy To..."),Key_F7,this,SLOT(copyFiles()),actionCollection(),"file_copy");
924
mMoveFiles=new KAction(i18n("&Move To..."),Key_F8,this,SLOT(moveFiles()),actionCollection(),"file_move");
925
mDeleteFiles=new KAction(i18n("&Delete"),"editdelete",Key_Delete,this,SLOT(deleteFiles()),actionCollection(),"file_delete");
926
mShowFileProperties=new KAction(i18n("Properties"),0,this,SLOT(showFileProperties()),actionCollection(),"file_properties");
927
KStdAction::quit( kapp, SLOT (closeAllWindows()), actionCollection() );
930
mRotateLeft=new KAction(i18n("Rotate &Left"),"rotate_left",CTRL + Key_L, this, SLOT(rotateLeft()),actionCollection(),"rotate_left");
931
mRotateRight=new KAction(i18n("Rotate &Right"),"rotate_right",CTRL + Key_R, this, SLOT(rotateRight()),actionCollection(),"rotate_right");
932
mMirror=new KAction(i18n("&Mirror"),"mirror",0, this, SLOT(mirror()),actionCollection(),"mirror");
933
mFlip=new KAction(i18n("&Flip"),"flip",0, this, SLOT(flip()),actionCollection(),"flip");
936
mReload=new KAction(i18n("Reload"), "reload", Key_F5, mDocument, SLOT(reload()), actionCollection(), "reload");
937
mReload->setEnabled(false);
939
mToggleFullScreen= KStdAction::fullScreen(this,SLOT(toggleFullScreen()),actionCollection(),0);
940
mStartSlideShow=new KAction(i18n("Slide Show..."),"slideshow",0,this,SLOT(startSlideShow()),actionCollection(),"slideshow");
943
mGoUp=new KToolBarPopupAction(i18n("Up"), "up", ALT + Key_Up, this, SLOT(goUp()), actionCollection(), "go_up");
944
new KAction( i18n( "Home" ), "gohome", KStdAccel::shortcut(KStdAccel::Home), this, SLOT(goHome()), actionCollection(), "go_home");
947
mResetDockWidgets = new KAction(i18n("Reset"), 0, this, SLOT(resetDockWidgets()), actionCollection(), "reset_dock_widgets");
951
KStdAction::preferences(this, SLOT(showConfigDialog()), actionCollection() );
953
KStdAction::keyBindings(this, SLOT(showKeyDialog()), actionCollection() );
954
(void)new KAction(i18n("Configure External Tools..."), "configure", 0,
955
this, SLOT(showExternalToolDialog()), actionCollection(), "configure_tools");
956
(void)KStdAction::configureToolbars(
957
this, SLOT(showToolBarDialog()), actionCollection() );
959
actionCollection()->readShortcutSettings();
964
* This method creates the interactions between objects, when it's called, all
965
* widgets and actions have already been created
967
void MainWindow::createObjectInteractions() {
969
mFileViewStack->listMode()->plug(mFileViewToolBar);
970
mFileViewStack->sideThumbnailMode()->plug(mFileViewToolBar);
971
mFileViewStack->bottomThumbnailMode()->plug(mFileViewToolBar);
972
actionCollection()->action("thumbnails_slider")->plug(mFileViewToolBar);
973
actionCollection()->action("thumbnail_details_dialog")->plug(mFileViewToolBar);
975
// Pixmap view caption formatter
976
mCaptionFormatter.reset( new CaptionFormatter(mFileViewStack, mDocument) );
977
mImageView->setOSDFormatter(mCaptionFormatter.get());
979
// Fullscreen actions in pixmap view
980
KActionPtrList actions;
981
actions.append(mFileViewStack->selectPrevious());
982
actions.append(mFileViewStack->selectNext());
983
actions.append(mToggleFullScreen);
984
mImageView->setFullScreenActions(actions);
986
// Make sure file actions are correctly updated
987
connect(mFileViewStack, SIGNAL(selectionChanged()),
988
this, SLOT(updateImageActions()) );
991
QString file = locate( "data", "kfile/bookmarks.xml" );
992
if (file.isEmpty()) {
993
file = locateLocal( "data", "kfile/bookmarks.xml" );
996
KBookmarkManager* manager=KBookmarkManager::managerForFile(file,false);
997
manager->setUpdate(true);
998
manager->setShowNSBookmarks(false);
1000
BookmarkViewController* ctrl=new BookmarkViewController(mBookmarkView, mBookmarkToolBar, manager);
1001
connect(ctrl, SIGNAL(openURL(const KURL&)),
1002
mFileViewStack,SLOT(setDirURL(const KURL&)) );
1003
connect(mFileViewStack, SIGNAL(directoryChanged(const KURL&)),
1004
ctrl, SLOT(setURL(const KURL&)) );
1006
BookmarkOwner* bookmarkOwner=new BookmarkOwner(this);
1008
KActionMenu* bookmark=new KActionMenu(i18n( "&Bookmarks" ), "bookmark", actionCollection(), "bookmarks" );
1009
new KBookmarkMenu(manager, bookmarkOwner, bookmark->popupMenu(), 0, true);
1011
connect(bookmarkOwner,SIGNAL(openURL(const KURL&)),
1012
mFileViewStack,SLOT(setDirURL(const KURL&)) );
1014
connect(mFileViewStack,SIGNAL(directoryChanged(const KURL&)),
1015
bookmarkOwner,SLOT(setURL(const KURL&)) );
1019
void MainWindow::createHideShowAction(KDockWidget* dock) {
1021
if (dock->mayBeHide()) {
1022
caption=i18n("Hide %1").arg(dock->caption());
1024
caption=i18n("Show %1").arg(dock->caption());
1027
KAction* action=new KAction(caption, 0, dock, SLOT(changeHideShowState()), (QObject*)0 );
1029
action->setIconSet( QIconSet(*dock->icon()) );
1031
mWindowListActions.append(action);
1035
void MainWindow::updateWindowActions() {
1036
unplugActionList("winlist");
1037
mWindowListActions.clear();
1038
createHideShowAction(mFolderDock);
1039
createHideShowAction(mBookmarkDock);
1040
createHideShowAction(mPixmapDock);
1041
createHideShowAction(mMetaDock);
1042
plugActionList("winlist", mWindowListActions);
1046
void MainWindow::createConnections() {
1047
connect(mGoUp->popupMenu(), SIGNAL(activated(int)),
1048
this,SLOT(goUpTo(int)));
1050
// Dir view connections
1051
connect(mDirView,SIGNAL(dirURLChanged(const KURL&)),
1052
mFileViewStack,SLOT(setDirURL(const KURL&)) );
1054
connect(mDirView, SIGNAL(dirRenamed(const KURL&, const KURL&)),
1055
this, SLOT(slotDirRenamed(const KURL&, const KURL&)) );
1057
// Pixmap view connections
1058
connect(mImageView,SIGNAL(selectPrevious()),
1059
mFileViewStack,SLOT(slotSelectPrevious()) );
1060
connect(mImageView,SIGNAL(selectNext()),
1061
mFileViewStack,SLOT(slotSelectNext()) );
1062
connect(mImageView,SIGNAL(zoomChanged(double)),
1063
this,SLOT(updateStatusInfo()) );
1064
connect(mImageView,SIGNAL(doubleClicked()),
1065
mToggleFullScreen,SLOT(activate()) );
1067
// File view connections
1068
connect(mFileViewStack,SIGNAL(urlChanged(const KURL&)),
1069
mDocument,SLOT(setURL(const KURL&)) );
1070
connect(mFileViewStack,SIGNAL(directoryChanged(const KURL&)),
1071
this,SLOT(slotDirURLChanged(const KURL&)) );
1072
connect(mFileViewStack,SIGNAL(directoryChanged(const KURL&)),
1073
mDirView,SLOT(setURL(const KURL&)) );
1074
connect(mFileViewStack,SIGNAL(directoryChanged(const KURL&)),
1075
mHistory,SLOT(addURLToHistory(const KURL&)) );
1077
connect(mFileViewStack,SIGNAL(completed()),
1078
this,SLOT(updateStatusInfo()) );
1079
connect(mFileViewStack,SIGNAL(canceled()),
1080
this,SLOT(updateStatusInfo()) );
1081
connect(mFileViewStack,SIGNAL(imageDoubleClicked()),
1082
mToggleFullScreen,SLOT(activate()) );
1083
connect(mFileViewStack,SIGNAL(shownFileItemRefreshed(const KFileItem*)),
1084
this,SLOT(slotShownFileItemRefreshed(const KFileItem*)) );
1085
connect(mFileViewStack,SIGNAL(sortingChanged()),
1086
this, SLOT(updateStatusInfo()) );
1088
// History connections
1089
connect(mHistory, SIGNAL(urlChanged(const KURL&)),
1090
mFileViewStack, SLOT(setDirURL(const KURL&)) );
1092
// Document connections
1093
connect(mDocument,SIGNAL(loading()),
1094
this,SLOT(slotImageLoading()) );
1095
connect(mDocument,SIGNAL(loaded(const KURL&)),
1096
this,SLOT(slotImageLoaded()) );
1097
connect(mDocument,SIGNAL(saved(const KURL&)),
1098
mFileViewStack,SLOT(updateThumbnail(const KURL&)) );
1099
connect(mDocument,SIGNAL(reloaded(const KURL&)),
1100
mFileViewStack,SLOT(updateThumbnail(const KURL&)) );
1103
connect(mSlideShow,SIGNAL(finished()),
1104
mToggleFullScreen,SLOT(activate()) );
1107
connect(mURLEdit, SIGNAL(activated(const QString &)),
1108
this,SLOT(slotGo()) );
1109
connect(mURLEdit, SIGNAL(returnPressed()),
1110
this,SLOT(slotGo()) );
1112
// Non configurable stop-fullscreen accel
1113
QAccel* accel=new QAccel(this);
1114
accel->connectItem(accel->insertItem(Key_Escape),this,SLOT(escapePressed()));
1117
connect(mDockArea->manager(), SIGNAL(change()),
1118
this, SLOT(updateWindowActions()) );
1122
void MainWindow::createLocationToolBar() {
1124
mURLEdit=new KHistoryCombo(this);
1125
mURLEdit->setDuplicatesEnabled(false);
1126
mURLEdit->setPixmapProvider(new KURLPixmapProvider);
1128
mURLEditCompletion=new KURLCompletion();
1129
//mURLEditCompletion->setDir("/");
1131
mURLEdit->setCompletionObject(mURLEditCompletion);
1132
mURLEdit->setAutoDeleteCompletionObject(true);
1134
KWidgetAction* comboAction=new KWidgetAction( mURLEdit, i18n("Location Bar"), 0,
1135
0, 0, actionCollection(), "location_url");
1136
comboAction->setShortcutConfigurable(false);
1137
comboAction->setAutoSized(true);
1140
(void)new KAction( i18n("Clear Location Bar"),
1141
QApplication::reverseLayout()?"clear_left" : "locationbar_erase",
1142
0, this, SLOT(clearLocationLabel()), actionCollection(), "clear_location");
1145
/* we use "kde toolbar widget" to avoid the flat background (looks bad with
1146
* styles like Keramik). See konq_misc.cc.
1148
QLabel* urlLabel=new QLabel(i18n("L&ocation:"), this, "kde toolbar widget");
1149
(void)new KWidgetAction( urlLabel, i18n("L&ocation: "), Key_F6, this, SLOT( activateLocationLabel()),
1150
actionCollection(), "location_label");
1151
urlLabel->setBuddy(mURLEdit);
1154
(void)new KAction(i18n("Go"), "key_enter", 0, this, SLOT(slotGo()), actionCollection(), "location_go");
1159
void MainWindow::clearLocationLabel() {
1160
mURLEdit->clearEdit();
1161
mURLEdit->setFocus();
1165
void MainWindow::activateLocationLabel() {
1166
mURLEdit->setFocus();
1167
mURLEdit->lineEdit()->selectAll();
1172
void MainWindow::loadPlugins() {
1174
Q_ASSERT(!mPluginLoader);
1175
if (mPluginLoader) return;
1177
// Not yet, wait until we're less busy
1178
if (BusyLevelManager::instance()->busyLevel() > BUSY_THUMBNAILS) {
1179
LOG("Too busy, wait");
1180
QTimer::singleShot(LOAD_PLUGIN_DELAY, this, SLOT(loadPlugins()) );
1184
LOG("Load plugins");
1185
// Sets up the plugin interface, and load the plugins
1186
KIPIInterface* interface = new KIPIInterface(this, mFileViewStack);
1187
mPluginLoader = new KIPI::PluginLoader(QStringList(), interface );
1188
connect( mPluginLoader, SIGNAL( replug() ), this, SLOT( slotReplug() ) );
1189
mPluginLoader->loadPlugins();
1193
// Helper class for slotReplug(), gcc does not want to instantiate templates
1194
// with local classes, so this is declared outside of slotReplug()
1197
QPtrList<KAction> mActions;
1199
MenuInfo(const QString& name) : mName(name) {}
1202
void MainWindow::slotReplug() {
1203
typedef QMap<KIPI::Category, MenuInfo> CategoryMap;
1204
CategoryMap categoryMap;
1205
categoryMap[KIPI::IMAGESPLUGIN]=MenuInfo("image_actions");
1206
categoryMap[KIPI::EFFECTSPLUGIN]=MenuInfo("effect_actions");
1207
categoryMap[KIPI::TOOLSPLUGIN]=MenuInfo("tool_actions");
1208
categoryMap[KIPI::IMPORTPLUGIN]=MenuInfo("import_actions");
1209
categoryMap[KIPI::EXPORTPLUGIN]=MenuInfo("export_actions");
1210
categoryMap[KIPI::BATCHPLUGIN]=MenuInfo("batch_actions");
1211
categoryMap[KIPI::COLLECTIONSPLUGIN]=MenuInfo("collection_actions");
1213
// Fill the mActions
1214
KIPI::PluginLoader::PluginList pluginList=mPluginLoader->pluginList();
1215
KIPI::PluginLoader::PluginList::ConstIterator it(pluginList.begin());
1216
KIPI::PluginLoader::PluginList::ConstIterator itEnd(pluginList.end());
1217
for( ; it!=itEnd; ++it ) {
1218
if (!(*it)->shouldLoad()) continue;
1219
KIPI::Plugin* plugin = (*it)->plugin();
1221
if (!plugin) continue;
1223
plugin->setup(this);
1224
KActionPtrList actions = plugin->actions();
1225
KActionPtrList::ConstIterator actionIt=actions.begin(), end=actions.end();
1226
for (; actionIt!=end; ++actionIt) {
1227
KIPI::Category category = plugin->category(*actionIt);
1229
if (!categoryMap.contains(category)) {
1230
kdWarning() << "Unknown category '" << category << "'\n";
1234
categoryMap[category].mActions.append(*actionIt);
1236
plugin->actionCollection()->readShortcutSettings();
1239
// Create a dummy "no plugin" action list
1240
KAction* noPlugin=new KAction(i18n("No Plugin"), 0, 0, 0, actionCollection(), "no_plugin");
1241
noPlugin->setShortcutConfigurable(false);
1242
noPlugin->setEnabled(false);
1243
QPtrList<KAction> noPluginList;
1244
noPluginList.append(noPlugin);
1247
CategoryMap::ConstIterator catIt=categoryMap.begin(), catItEnd=categoryMap.end();
1248
for (; catIt!=catItEnd; ++catIt) {
1249
const MenuInfo& info=catIt.data();
1250
unplugActionList(info.mName);
1251
if (info.mActions.count()>0) {
1252
plugActionList(info.mName, info.mActions);
1254
plugActionList(info.mName, noPluginList);
1259
void MainWindow::loadPlugins() {
1260
QPopupMenu *popup = static_cast<QPopupMenu*>(
1261
factory()->container( "plugins", this));
1266
void MainWindow::slotReplug() {
1271
//-----------------------------------------------------------------------
1275
//-----------------------------------------------------------------------
1276
void MainWindow::setShowBusyPtrInFullScreen(bool value) {
1277
mShowBusyPtrInFullScreen=value;
1280
void MainWindow::setAutoDeleteThumbnailCache(bool value){
1281
mAutoDeleteThumbnailCache=value;
1285
//-----------------------------------------------------------------------
1289
//-----------------------------------------------------------------------
1290
void MainWindow::readConfig(KConfig* config,const QString& group) {
1291
config->setGroup(group);
1292
mShowBusyPtrInFullScreen=config->readBoolEntry(CONFIG_BUSYPTR_IN_FS, true);
1293
mAutoDeleteThumbnailCache=config->readBoolEntry(CONFIG_AUTO_DELETE_THUMBNAIL_CACHE, false);
1297
void MainWindow::writeConfig(KConfig* config,const QString& group) const {
1298
config->setGroup(group);
1299
config->writeEntry(CONFIG_BUSYPTR_IN_FS, mShowBusyPtrInFullScreen);
1300
config->writeEntry(CONFIG_AUTO_DELETE_THUMBNAIL_CACHE, mAutoDeleteThumbnailCache);