diff --git a/ChangeLog b/ChangeLog index 78a31e1c..bac1021d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,399 +1,404 @@ +2004-04-19 Jesper K. Pedersen + + * BUGFIX: If description was not generated then other option + groups was not printed in HTML exports. + 2004-04-18 Jesper K. Pedersen * When opening the image config dialog, show a message box with a link to the help page. * Made it possible to re enable message boxes where the user previously checked do-not-show-again * Its now possible to find images where only a set of items are on (e.g. only me, and no one else) * BUGFIX: When generating HTML, only generate image on disk * Added a dialog with a description on how to enable webservers to server KimDaBa files. 2004-04-16 Jesper K. Pedersen * BUGFIX: If the destination directory for HTML export exists, offer to remove it. This fixes the problem where it would instead just be put in a subdirectory. * Loading descriptions from EXIF information can now be disabled * BUGFIX: when exporting the image loader also saved the large images (like 1024x768) to tumbnails dir. Please remove all thumbnails using the maintenance menu item. * BUGFIX: images inline in export files was broken if the extension was different from .jpg * Now its possible to ask for a .kim file on the HTML generated pages * BUGFIX: pressing cancel in export dialog still continue exporting. * BUGFIX: It was not possible to import twice in one session. * BUGFIX: images was rotated too must during export * now its possible to export images, and leave the .kim file next to the image set rather than putting them into the .kim file. 2004-04-15 Jesper K. Pedersen * Its now possible to delete images from within the image configuration dialog * Now you may click on a .kim file from say konqueror to start importing that file into your db. 2004-04-14 Jesper K. Pedersen * added Import/Export so its possible to share images with friends, without them having to write comments, and tell how is on the images. 2004-04-12 Jesper K. Pedersen * Its now possible to configure the toolbar * Added run slide show as a tool button * Now its possible to configure the shortcuts in the viewer. 2004-04-11 Jesper K. Pedersen * added run randomized slideshow * added run slide show to the thumbnail view, thus making it much easier to start a slide show if the images in view. * Made slide show timeout configurable * Made slide show size configurable, plus made it possible to specify full screen for configuration for configuration of normal view. 2004-03-27 Jesper K. Pedersen * rewrote the handling of dates in the image property dialog, so - the GUI is must easier to work with - this must have been the + the GUI is much easier to work with - this must have been the oldest wish on my which list ;-) 2004-03-21 Jesper K. Pedersen * Added Images->sort to sort images in thumbnail view. Thanks to Thomas Schwarzgruber * Added Maintenance->remove all thumbnails and Maintenance->build thumbnails 2004-03-20 Jesper K. Pedersen * BUGFIX: now we are doing boundary check when panning, so you can't pan outside the image. * generating HTML and viewing images will now be the context if no images are selected. Context is the current search or current browse - e.g. all images from say Las Vegas. 2004-03-17 Jesper K. Pedersen * Added context menu for sorting options listbox (thanks to Reimar Imhof for a patch) 2004-03-10 Jesper K. Pedersen * BUGFIX: Fixed crash when moving images arround 2004-03-09 Jesper K. Pedersen * BUGFIX: If you have to rotate an image to view it, you get black stripes besides your image because of the resolution of the image (it's much higher than wide). So far so good. But if you zoom into the image via pressing '+' key, the black stripes don't change -> the shown width stays the same although the (virtually) height changed. Thanks to Thomas Schwarzgruber for a patch. 2004-03-07 Jesper K. Pedersen * BUGFIX: When renaming an item in the listselect, then category image is now also renamed. * BUGFIX: In the settings dialog, member group tab, ensure that the category list is updated when entering the page. * replaced "None" with "No Persons", "No Keywords" etc. * the count text in the browser is now "categories" rather than "images" when displaying categories like "persons", "locations" etc. * BUGFIX: Finally made panning work. Its now bound to the middle mouse button, which is more compatible to a wide range of application, rather than Ctrl+left button as was the case previously. 2004-03-02 Jesper K. Pedersen * BUGFIX: previous fix to member groups was broken. * use smoothScale rather than scale to get better looking thumbnails. 2004-02-15 Jesper K. Pedersen * BUGFIX: Pressing the rename button in member groups made KimDaBa crash if no member groups are selected. --------------------------- version 1.1 released -------------------------------------- 2004-02-04 Jesper K. Pedersen * BUGFIX: description on index page was controlled by "description" checkbox rather than the description for each page 2004-02-01 Jesper K. Pedersen * BUGFIX: option groups was not available for translations. * BUGFIX: the string **NONE** was not made available for translation everywhere, which resulted in the search dialog did not work for translated languages. 2004-01-31 Jesper K. Pedersen * BUGFIX: changed viewer from QDialog to QWidget as base class so the browser window could get on top of it. 2004-01-29 Jesper K. Pedersen * Made the image preview size configurable. * Ensure enable/disable state of menu bar is correct 2004-01-27 Jesper K. Pedersen * Made the KimDaBa properties dialog look better. 2004-01-26 Jesper K. Pedersen * BUGFIX: Changed QActions to KActions in the viewer to avoid mem error when the viewer closes. * BUGFIX: Fixed bug introduced yesterday, where rotating multiple images resulting in them getting an odd angle. 2004-01-25 Jesper K. Pedersen * Split up the dialog for HTML generation, plus made it possible to specify which of the option groups (Persons/Location/...) plus description - to generate. * The image configuration dialog may now be closed by pressing Ctrl+return * Added a number of tooltips * Added a donate dialog, which makes it possible for people to donate money. * BUGFIX: when generating HTML, its no longer a problem if several images have the same base name, ie. if you may now generate holiday1/me.jpg andd holiday2/me.jpg at the same time. * BUGFIX: When the user presses the right mouse button on one of the list boxes containing options (Persons, Loactions, Keywords etc.) to show the context menu, then the state of the item was changed (from selected to non-selected or visa versa). * The total amount of images in the status bar is now updated when new images are found or existing images are deleted. * BUGFIX: don't load the search and multi-config images through the imageinfo clas as this will make KimDaBa ask whether date should be trusted. * Added a configuration option for whether EXIF rotation information should be used or not. 2004-01-23 Jesper K. Pedersen * BUGFIX: It was not possible to generate HTML more than once per session. * Read date, orientation and description out of EXIF data. 2004-01-21 Jesper K. Pedersen * Thanks to Teemu Rytilahti , KimDaBa will now offer themes when generating HTML. * Heavily optimized browsing functions. Now everything is hopefully lightning fast. 2004-01-20 Jesper K. Pedersen * The thumbnail overview and the image viewer now has a menu item for invoking an external program on the images. The list includes all programs claiming they can handle image/jpeg from KTrader. * Implemented Maintenance/Display Images not on Disk * Implemented Maintenance/Recalculate Checksum (Useful if images has been change for example using gimp) * Implemented Maintenance/Rescan for new Images * Only do auto save if there has been changes since the last auto save. 2004-01-19 Jesper K. Pedersen * MD5 sums are now calculated for each image, so that KimDaBa can track movement of images in the directories 2004-01-18 Jesper K. Pedersen * Move cursor to the lower right corner when viewer goes into fullscreen mode * BUGFIX: Generate HTML with nothing selected now export all images from thumbnail view. * BUGFIX: Context menu for thumbnail view used to show up in the browser too. * BUGFIX: searches using the textbox didn't work. * BUGFIX: ensure that tip of the day has focus when it starts up. 2004-01-10 Jesper K. Pedersen * Improved HTML generation. 2004-01-04 Jesper K. Pedersen * The tool tip for the thumbnail view now contains an enlargement of the image. In addition the tool tip needs to be disabled, rather than it automatically hides. The tool tip window will temporarily hide when the mouse is outside the thumbnail view. The placement of the tool tip window is now improved, so it doesn't get partly of screen. 2004-01-03 Jesper K. Pedersen * Added an item to the context menu in the viewer for setting the current image as the background. (Thanks to Teemu Rytilahti ) for a patch with this feature. * New Feature: It is now possible to show the content views (those with overview of persons, locations, keywords etc) either with a list view or with an icon view. In addition it is also possible to show a different icon for each item (one icon for Joe, and another for Bill). 2003-12-30 Jesper K. Pedersen * BUGFIX: Member groups are not shown in the browser, in case the member group do not contain any items. 2003-12-26 Jesper K. Pedersen * Update thumnail view when an image has been rotated. * Added "View Selected" and "View Selected in new window" to the context menu for the thumbnail overview. * Enable/Disable state of "configure property items" are now correctly set. * On public demand, the file name is now shown in the status bar. 2003-12-13 Jesper K. Pedersen * BUGFIX: fixed crash where KimDaBa crashes if you right click outside an item in one of the list boxes with properties (Persons, Locations, ...) 2003-12-05 Jesper K. Pedersen * BUGFIX: KimDaBa used to crash on moving images around. 2003-12-01 Jesper K. Pedersen * New Feature: Its now possible to drag(copy) images from kimdaba to say the desktop. Unfortunately KimDaBa crashes in KDE code if I drag an QImage out, so I can only drag the filename out, which means that rotated images are not rotated when dragged out. Still better than nothing ;-) * Go out of full screen if an item from the info box in the viewer is selected, and the viewer is on the same monitor as the browser. * Added Settings | Configure Shortcuts * Edit->Options was moved Settings->Configure Kimdaba. * New Feature: It is now possible to using fish:// or ftp:// when exporting to HTML * BUGFIX: Don't show HTML export dialog in case no item was selected. ---------------------------------- version 1.0 released -------------------- 2003-11-27 Jesper K. Pedersen * BUGFIX: Previously the image loader was asked to load all images on start up, making machines with low memory crash. This was clearly unintentional, and as such a bug. 2003-11-21 Jesper K. Pedersen * BUGFIX: indicator marks are now properly shown during selection of drawing on images. 2003-11-13 Jesper K. Pedersen * BUGFIX: File names did not contain an extension in the ThumbNail directory. This resulted in a name class if two files existed with same base name but different extension. * Completed the KimDaBa handbook. * BUGFIX: KimDaBa did always show one image less than the index promised. * IMPROVEMENT: Exchanged Ctrl+plus and Ctrl+minus in the viewer, so ctrl+plus now means run faster and ctrl+minus means run slower. This seems much more intuitive. 2003-10-21 Jesper K. Pedersen * BUGFIX: First search for an image, then set properties, and the app crashed. 2003-10-05 Jesper K. Pedersen * BUGFIX: KimDaBa crashed when it found new images at start up. * Started writing a handbook for KimDaBa. * BUGFIX: if the slideshow was running very fast, then keyevents got utterly much behind making it almost impossible to stop the slideshow. * Its now possible to configure image properties from within the viewer. 2003-10-04 Jesper K. Pedersen * Added new feature, which allows you to specify a default search option, that applies to all searches. That way you can exclude all private images, when looking at images with say, your parents. * BUGFIX: If a user added a new group, but never added any items to the group, then the group would not be available later for adding new items, but it was still available for selecting in configuration listbox and for searching. * BUGFIX: When a group was renamed or delete, the old name would still be available in the configuration listbox. * Added status bar icon for dirtyness. * BUGFIX: In the image config, selecting an item from the listbox did not mark the image dirty. * BUGFIX: Pressing Cancel in the find dialog, does no longer change the content of the browser window. diff --git a/htmlexportdialog.cpp b/htmlexportdialog.cpp index 20c643fd..cef9870b 100644 --- a/htmlexportdialog.cpp +++ b/htmlexportdialog.cpp @@ -1,833 +1,833 @@ /* * Copyright (c) 2003-2004 Jesper K. Pedersen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2 as published by the Free Software Foundation. * * 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., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. **/ #include "kdeversion.h" #include "htmlexportdialog.h" #include #include #include #include #include #include #include #include #include #include "imagemanager.h" #include #include #include #include #include "options.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "util.h" #include #include #include #include #include #include #include "export.h" #include "mainview.h" class ImageSizeCheckBox :public QCheckBox { public: ImageSizeCheckBox( int width, int height, QWidget* parent ) :QCheckBox( QString::fromLatin1("%1x%2").arg(width).arg(height), parent ), _width( width ), _height( height ) { } ImageSizeCheckBox( const QString& text, QWidget* parent ) :QCheckBox( text, parent ), _width( -1 ), _height( -1 ) { } int width() const { return _width; } int height() const { return _height; } QString text( bool withOutSpaces ) const { return text( _width, _height, withOutSpaces ); } static QString text( int width, int height, bool withOutSpaces ) { if ( width == -1 ) if ( withOutSpaces ) return QString::fromLatin1("fullsize"); else return QString::fromLatin1("full size"); else return QString::fromLatin1("%1x%2").arg(width).arg(height); } private: int _width; int _height; }; HTMLExportDialog::HTMLExportDialog( QWidget* parent, const char* name ) :KDialogBase( IconList, i18n("HTML Export"), Ok|Cancel, Ok, parent, name ) { enableButtonOK( false ); createContentPage(); createLayoutPage(); createDestinationPage(); } void HTMLExportDialog::createContentPage() { QWidget* contentPage = addPage( i18n("Content" ), i18n("Content" ), KGlobal::iconLoader()->loadIcon( QString::fromLatin1( "edit" ), KIcon::Desktop, 32 )); QVBoxLayout* lay1 = new QVBoxLayout( contentPage, 6 ); QGridLayout* lay2 = new QGridLayout( lay1, 2 ); QLabel* label = new QLabel( i18n("Page title:"), contentPage ); lay2->addWidget( label, 0, 0 ); _title = new KLineEdit( contentPage ); lay2->addWidget( _title, 0, 1 ); // Description label = new QLabel( i18n("Description:"), contentPage ); label->setAlignment( Qt::AlignTop ); lay2->addWidget( label, 1, 0 ); _description = new QTextEdit( contentPage ); lay2->addWidget( _description, 1, 1 ); _generateKimFile = new QCheckBox( i18n("Create .kim export file"), contentPage ); _generateKimFile->setChecked( true ); lay1->addWidget( _generateKimFile ); // What to include QVGroupBox* whatToInclude = new QVGroupBox( i18n( "What to Include" ), contentPage ); lay1->addWidget( whatToInclude ); QWidget* w = new QWidget( whatToInclude ); QGridLayout* lay3 = new QGridLayout( w, 1, 2, 6 ); lay3->setAutoAdd( true ); QStringList optionGroups = Options::instance()->optionGroups(); for( QStringList::Iterator it = optionGroups.begin(); it != optionGroups.end(); ++it ) { QCheckBox* cb = new QCheckBox( Options::instance()->textForOptionGroup(*it), w ); _whatToIncludeMap.insert( *it, cb ); } QCheckBox* cb = new QCheckBox( i18n("Description"), w ); _whatToIncludeMap.insert( QString::fromLatin1("**DESCRIPTION**"), cb ); } void HTMLExportDialog::createLayoutPage() { QWidget* layoutPage = addPage( i18n("Layout" ), i18n("Layout" ), KGlobal::iconLoader()->loadIcon( QString::fromLatin1( "matrix" ), KIcon::Desktop, 32 )); QVBoxLayout* lay1 = new QVBoxLayout( layoutPage, 6 ); QGridLayout* lay2 = new QGridLayout( lay1, 2, 2, 6 ); // Thumbnail size QLabel* label = new QLabel( i18n("Thumbnail size:"), layoutPage ); lay2->addWidget( label, 0, 0 ); QHBoxLayout* lay3 = new QHBoxLayout( 0 ); lay2->addLayout( lay3, 0, 1 ); _thumbSize = new QSpinBox( 16, 256, 1, layoutPage ); _thumbSize->setValue( 128 ); lay3->addWidget( _thumbSize ); lay3->addStretch(1); // Number of columns label = new QLabel( i18n("Number of columns:"), layoutPage ); lay2->addWidget( label, 1, 0 ); QHBoxLayout* lay4 = new QHBoxLayout( 0 ); lay2->addLayout( lay4, 1, 1 ); _numOfCols = new QSpinBox( 1, 10, 1, layoutPage ); _numOfCols->setValue( 5 ); lay4->addWidget( _numOfCols ); lay4->addStretch( 1 ); // Theme box label = new QLabel( i18n("Theme:"), layoutPage ); lay2->addWidget( label, 2, 0 ); lay4 = new QHBoxLayout( 0 ); lay2->addLayout( lay4, 2, 1 ); _themeBox = new QComboBox( layoutPage, "theme_combobox" ); lay4->addWidget( _themeBox ); lay4->addStretch( 1 ); populateThemesCombo(); // Image sizes QHGroupBox* sizes = new QHGroupBox( i18n("Image Sizes"), layoutPage ); lay1->addWidget( sizes ); QWidget* content = new QWidget( sizes ); QGridLayout* lay5 = new QGridLayout( content, 2, 4 ); lay5->setAutoAdd( true ); ImageSizeCheckBox* size320 = new ImageSizeCheckBox( 320, 200, content ); ImageSizeCheckBox* size640 = new ImageSizeCheckBox( 640, 480, content ); ImageSizeCheckBox* size800 = new ImageSizeCheckBox( 800, 600, content ); ImageSizeCheckBox* size1024 = new ImageSizeCheckBox( 1024, 768, content ); ImageSizeCheckBox* size1280 = new ImageSizeCheckBox( 1280, 1024, content ); ImageSizeCheckBox* size1600 = new ImageSizeCheckBox( 1600, 1200, content ); ImageSizeCheckBox* sizeOrig = new ImageSizeCheckBox( i18n("Full size"), content ); size800->setChecked( 1 ); _cbs << size320 << size640 << size800 << size1024 << size1280 << size1600 << sizeOrig; _preferredSizes << size800 << size1024 << size1280 << size640 << size1600 << size320 << sizeOrig; lay1->addStretch(1); } void HTMLExportDialog::createDestinationPage() { QWidget* destinationPage = addPage( i18n("Destination" ), i18n("Destination" ), KGlobal::iconLoader()->loadIcon( QString::fromLatin1( "hdd_unmount" ), KIcon::Desktop, 32 )); QVBoxLayout* lay1 = new QVBoxLayout( destinationPage, 6 ); QGridLayout* lay2 = new QGridLayout( lay1, 2 ); // Base Directory QLabel* label = new QLabel( i18n("Base directory:"), destinationPage ); lay2->addWidget( label, 5, 0 ); QHBoxLayout* lay3 = new QHBoxLayout( (QWidget*)0, 0, 6 ); lay2->addLayout( lay3, 5, 1 ); _baseDir = new KLineEdit( destinationPage ); lay3->addWidget( _baseDir ); QPushButton* but = new QPushButton( QString::fromLatin1( ".." ), destinationPage ); lay3->addWidget( but ); but->setFixedWidth( 25 ); connect( but, SIGNAL( clicked() ), this, SLOT( selectDir() ) ); _baseDir->setText( Options::instance()->HTMLBaseDir() ); // Base URL label = new QLabel( i18n("Base URL:"), destinationPage ); lay2->addWidget( label, 6, 0 ); _baseURL = new KLineEdit( destinationPage ); _baseURL->setText( Options::instance()->HTMLBaseURL() ); lay2->addWidget( _baseURL, 6, 1 ); // Output Directory label = new QLabel( i18n("Output directory:"), destinationPage ); lay2->addWidget( label, 7, 0 ); _outputDir = new KLineEdit( destinationPage ); lay2->addWidget( _outputDir, 7, 1 ); lay1->addStretch( 1 ); } bool HTMLExportDialog::generate() { if ( !checkVars() ) return false; hide(); _tempDir = KTempDir().name(); // Generate .kim file if ( _generateKimFile->isChecked() ) { bool ok; Export* exp = new Export( _list, kimFileName( false ), false, -1, ManualCopy, ok ); delete exp; // It will not return before done - we still need a class to connect slots etc. if ( !ok ) return false; } // prepare the progress dialog _total = _waitCounter = calculateSteps(); _progress->setTotalSteps( _total ); _progress->setProgress( 0 ); connect( _progress, SIGNAL( cancelled() ), this, SLOT( slotCancelGenerate() ) ); _nameMap = Util::createUniqNameMap( _list, false, QString::null ); // Itertate over each of the image sizes needed. for( QValueList::Iterator sizeIt = _cbs.begin(); sizeIt != _cbs.end(); ++sizeIt ) { if ( (*sizeIt)->isChecked() ) { bool ok = generateIndexPage( (*sizeIt)->width(), (*sizeIt)->height() ); if ( !ok ) return false; for ( uint index = 0; index < _list.count(); ++index ) { ImageInfo* info = _list.at(index); ImageInfo* prev = 0; ImageInfo* next = 0; if ( index != 0 ) prev = _list.at(index-1); if ( index != _list.count() -1 ) next = _list.at(index+1); ok = generateContextPage( (*sizeIt)->width(), (*sizeIt)->height(), prev, info, next ); if (!ok) return false; } } } // Now generate the thumbnail images for( ImageInfoListIterator it( _list ); *it; ++it ) { #if QT_VERSION < 0x030104 if ( _progress->wasCancelled() ) return false; #else if ( _progress->wasCanceled() ) return false; #endif createImage( *it, _thumbSize->value() ); } bool ok = linkIndexFile(); if ( !ok ) return false; if ( _waitCounter > 0 ) qApp->eventLoop()->enterLoop(); // Copy over the mainpage.css, indepage.css QString themeDir, themeAuthor, themeName; getThemeInfo( &themeDir, &themeName, &themeAuthor ); QDir dir( themeDir ); QStringList files = dir.entryList( QDir::Files ); if( files.count() < 1 ) kdDebug() << QString::fromLatin1("theme '%1' doesn't have enough files to be a theme").arg( themeDir ) << endl; for( QStringList::Iterator it = files.begin(); it != files.end(); ++it ) { if( *it == QString::fromLatin1("kimdaba.theme") || *it == QString::fromLatin1("mainpage.html") || *it == QString::fromLatin1("imagepage.html")) continue; QString from = QString::fromLatin1("%1%2").arg( themeDir ).arg(*it); QString to = _tempDir+QString::fromLatin1("/") + *it; ok = Util::copy( from, to ); if ( !ok ) { KMessageBox::error( this, i18n("Error copying %1 to %2").arg( from ).arg( to ) ); return false; } } // Copy files over to destination. QString outputDir = _baseDir->text() + QString::fromLatin1( "/" ) + _outputDir->text(); KIO::CopyJob* job = KIO::move( KURL(_tempDir), KURL(outputDir) ); connect( job, SIGNAL( result( KIO::Job* ) ), this, SLOT( showBrowser() ) ); return true; } bool HTMLExportDialog::generateIndexPage( int width, int height ) { QString themeDir, themeAuthor, themeName; getThemeInfo( &themeDir, &themeName, &themeAuthor ); QString content = Util::readFile( QString::fromLatin1( "%1mainpage.html" ).arg( themeDir ) ); if ( content.isNull() ) return false; content = QString::fromLatin1("\n").arg( themeName ).arg( themeAuthor ) + content; content.replace( QString::fromLatin1( "**DESCRIPTION**" ), _description->text() ); content.replace( QString::fromLatin1( "**TITLE**" ), _title->text() ); QString kimLink = QString::fromLatin1( "Share and Enjoy KimDaBa export file" ).arg( kimFileName( true ) ); if ( _generateKimFile->isChecked() ) content.replace( QString::fromLatin1( "**KIMFILE**" ), kimLink ); else content.replace( QString::fromLatin1( "**KIMFILE**" ), QString::null ); QDomDocument doc; QDomElement elm; QDomElement col; // -------------------------------------------------- Thumbnails // Initially all of the HTML generation was done using QDom, but it turned out in the end // to be much less code simply concatenating strings. This part, however, is easier using QDom // so we keep it using QDom. int count = 0; int cols = _numOfCols->value(); QDomElement row; for( ImageInfoListIterator it( _list ); *it; ++it ) { #if QT_VERSION < 0x030104 if ( _progress->wasCancelled() ) return false; #else if ( _progress->wasCanceled() ) return false; #endif if ( count % cols == 0 ) { row = doc.createElement( QString::fromLatin1( "tr" ) ); row.setAttribute( QString::fromLatin1( "class" ), QString::fromLatin1( "thumbnail-row" ) ); doc.appendChild( row ); count = 0; } col = doc.createElement( QString::fromLatin1( "td" ) ); col.setAttribute( QString::fromLatin1( "class" ), QString::fromLatin1( "thumbnail-col" ) ); row.appendChild( col ); QDomElement href = doc.createElement( QString::fromLatin1( "a" ) ); href.setAttribute( QString::fromLatin1( "href" ), namePage( width, height, (*it)->fileName(false) ) ); col.appendChild( href ); QDomElement img = doc.createElement( QString::fromLatin1( "img" ) ); img.setAttribute( QString::fromLatin1( "src" ), nameImage( (*it)->fileName(), _thumbSize->value() ) ); img.setAttribute( QString::fromLatin1( "alt" ), nameImage( (*it)->fileName(), _thumbSize->value() ) ); href.appendChild( img ); ++count; } content.replace( QString::fromLatin1( "**THUMBNAIL-TABLE**" ), doc.toString() ); // -------------------------------------------------- Resolutions QString resolutions; QValueList actRes = activeResolutions(); if ( actRes.count() > 1 ) { resolutions += QString::fromLatin1( "Resolutions: " ); for( QValueList::Iterator sizeIt = actRes.begin(); sizeIt != actRes.end(); ++sizeIt ) { int w = (*sizeIt)->width(); int h = (*sizeIt)->height(); QString page = QString::fromLatin1( "index-%1.html" ) .arg( ImageSizeCheckBox::text( w, h, true ) ); QString text = (*sizeIt)->text(false); resolutions += QString::fromLatin1( " " ); if ( width == w && height == h ) { resolutions += text; } else { resolutions += QString::fromLatin1( "%2" ).arg( page ).arg( text ); } } } content.replace( QString::fromLatin1( "**RESOLUTIONS**" ), resolutions ); #if QT_VERSION < 0x030104 if ( _progress->wasCancelled() ) return false; #else if ( _progress->wasCanceled() ) return false; #endif // -------------------------------------------------- write to file QString fileName = _tempDir + QString::fromLatin1("/index-%1.html" ) .arg(ImageSizeCheckBox::text(width,height,true)); bool ok = writeToFile( fileName, content ); if ( !ok ) return false; return true; } bool HTMLExportDialog::generateContextPage( int width, int height, ImageInfo* prevInfo, ImageInfo* info, ImageInfo* nextInfo ) { QString themeDir, themeAuthor, themeName; getThemeInfo( &themeDir, &themeName, &themeAuthor ); QString content = Util::readFile( QString::fromLatin1( "%1imagepage.html" ).arg( themeDir )); if ( content.isNull() ) return false; content = QString::fromLatin1("\n").arg( themeName ).arg( themeAuthor ) + content; content.replace( QString::fromLatin1( "**TITLE**" ), info->label() ); content.replace( QString::fromLatin1( "**IMAGE**" ), createImage( info, width ) ); // -------------------------------------------------- Links QString link; // prev link if ( prevInfo ) link = QString::fromLatin1( "prev" ).arg( namePage( width, height, prevInfo->fileName() ) ); else link = QString::fromLatin1( "prev" ); content.replace( QString::fromLatin1( "**PREV**" ), link ); // index link link = QString::fromLatin1( "index" ).arg(ImageSizeCheckBox::text(width,height,true)); content.replace( QString::fromLatin1( "**INDEX**" ), link ); // Next Link if ( nextInfo ) link = QString::fromLatin1( "next" ).arg( namePage( width, height, nextInfo->fileName() ) ); else link = QString::fromLatin1( "next" ); content.replace( QString::fromLatin1( "**NEXT**" ), link ); if ( nextInfo ) link = namePage( width, height, nextInfo->fileName() ); else link = QString::fromLatin1( "index-%1.html" ).arg(ImageSizeCheckBox::text(width,height,true)); content.replace( QString::fromLatin1( "**NEXTPAGE**" ), link ); // -------------------------------------------------- Resolutions QString resolutions; QValueList actRes = activeResolutions(); if ( actRes.count() > 1 ) { for( QValueList::Iterator sizeIt = actRes.begin(); sizeIt != actRes.end(); ++sizeIt ) { int w = (*sizeIt)->width(); int h = (*sizeIt)->height(); QString page = namePage( w, h, info->fileName() ); QString text = (*sizeIt)->text(false); resolutions += QString::fromLatin1( " " ); if ( width == w && height == h ) resolutions += text; else resolutions += QString::fromLatin1( "%2" ).arg( page ).arg( text ); } } content.replace( QString::fromLatin1( "**RESOLUTIONS**" ), resolutions ); // -------------------------------------------------- Description QString description; QStringList optionGroups = Options::instance()->optionGroups(); for( QStringList::Iterator it = optionGroups.begin(); it != optionGroups.end(); ++it ) { if ( info->optionValue( *it ).count() != 0 && _whatToIncludeMap[*it]->isChecked() ) { QString val = info->optionValue( *it ).join( QString::fromLatin1(", ") ); description += QString::fromLatin1("
  • %1: %2\n").arg( *it ).arg( val ); } } - if ( !info->description().isEmpty() ) { + if ( !info->description().isEmpty() && _whatToIncludeMap[QString::fromLatin1( "**DESCRIPTION**" )]->isChecked() ) { description += QString::fromLatin1( "
  • Description: %1\n" ).arg( info->description() ); } - if ( _whatToIncludeMap[QString::fromLatin1( "**DESCRIPTION**" )]->isChecked() ) + if ( !description.isEmpty() ) content.replace( QString::fromLatin1( "**DESCRIPTION**" ), QString::fromLatin1( "
      \n%1\n
    " ).arg( description ) ); else content.replace( QString::fromLatin1( "**DESCRIPTION**" ), QString::fromLatin1( "" ) ); // -------------------------------------------------- write to file QString fileName = _tempDir + namePage( width, height, info->fileName() ); bool ok = writeToFile( fileName, content ); if ( !ok ) return false; return true; } bool HTMLExportDialog::writeToFile( const QString& fileName, const QString& str ) { QFile file(fileName); if ( !file.open(IO_WriteOnly) ) { KMessageBox::error( this, i18n("Could not create file '%1'.").arg(fileName), i18n("Could Not Create File") ); return false; } QCString cstr = str.utf8(); file.writeBlock( cstr.data(), cstr.size() - 1); file.close(); return true; } QString HTMLExportDialog::createImage( ImageInfo* info, int size ) { ImageManager::instance()->load( info->fileName(), this, info->angle(), size, size, false, true ); return nameImage( info->fileName(), size ); } void HTMLExportDialog::pixmapLoaded( const QString& fileName, int size, int /*height*/, int /*angle*/, const QImage& image ) { _progress->setProgress( _total - _waitCounter ); _waitCounter--; QString file = _tempDir + QString::fromLatin1( "/" ) + nameImage( fileName, size ); bool success = image.save( file, "JPEG" ); if ( !success ) { // We better stop the imageloading. In case this is a full disk, we will just get all images loaded, while this // error box is showing, resulting in a bunch of error messages, and memory running out due to all the hanging // pixmapLoaded methods. slotCancelGenerate(); KMessageBox::error( this, i18n("Unable to write image '%1'.").arg(file) ); } if ( _waitCounter == 0 ) { qApp->eventLoop()->exitLoop(); } } void HTMLExportDialog::slotOk() { if( activeResolutions().count() < 1 ) { KMessageBox::error( 0, i18n( "You must select at least one resolution." ) ); return; } // Progress dialog _progress = new QProgressDialog( i18n("Generating images for HTML page "), i18n("&Cancel"), 0, this ); bool ok = generate(); if ( ok ) { Options::instance()->setHTMLBaseDir( _baseDir->text() ); Options::instance()->setHTMLBaseURL( _baseURL->text() ); accept(); } delete _progress; _progress = 0; } void HTMLExportDialog::selectDir() { KURL dir = KFileDialog::getExistingURL( _baseDir->text(), this ); if ( !dir.url().isNull() ) _baseDir->setText( dir.url() ); } void HTMLExportDialog::slotCancelGenerate() { ImageManager::instance()->stop( this ); _waitCounter = 0; } void HTMLExportDialog::showBrowser() { if ( _generateKimFile->isChecked() ) Export::showUsageDialog(); if ( ! _baseURL->text().isEmpty() ) new KRun( KURL(QString::fromLatin1( "%1/%2/index.html" ).arg( _baseURL->text() ).arg( _outputDir->text()) ) ); } bool HTMLExportDialog::checkVars() { QString outputDir = _baseDir->text() + QString::fromLatin1( "/" ) + _outputDir->text(); // Ensure base dir is specified QString baseDir = _baseDir->text(); if ( baseDir.isEmpty() ) { KMessageBox::error( this, i18n("You did not specify a base directory. " "This is the topmost directory for your images. " "Under this directory you will find each generated collection " "in separate directories."), i18n("No Base Directory Specified") ); return false; } // ensure output directory is specified if ( _outputDir->text().isEmpty() ) { KMessageBox::error( this, i18n("You did not specify an output directory. " "This is a directory containing the actual images. " "The directory will be in the base directory specified above."), i18n("No Output Directory Specified") ); return false; } // ensure base dir exists KIO::UDSEntry result; #if KDE_IS_VERSION( 3,1,90 ) bool ok = KIO::NetAccess::stat( KURL(baseDir), result, this ); #else bool ok = KIO::NetAccess::stat( KURL(baseDir), result ); #endif if ( !ok ) { KMessageBox::error( this, i18n("Error while reading information about %1. " "This is most likely because the directory does not exist.") .arg( baseDir ) ); return false; } KFileItem fileInfo( result, KURL(baseDir) ); if ( !fileInfo.isDir() ) { KMessageBox::error( this, i18n("%1 does not exist, is not a directory or " "cannot be written to.").arg( baseDir ) ); return false; } // test if destination directory exists. #if KDE_IS_VERSION( 3, 1, 90 ) bool exists = KIO::NetAccess::exists( KURL(outputDir), false, MainView::theMainView() ); #else bool exists = KIO::NetAccess::exists( KURL(outputDir) ); #endif if ( exists ) { int answer = KMessageBox::warningYesNo( this, i18n("

    Output directory %1 already exists. " "Usually you should specify a new directory.

    " "Should I delete %2 first?
    ").arg( outputDir ).arg( outputDir ), i18n("Directory Exists"), KStdGuiItem::yes(), KStdGuiItem::no(), QString::fromLatin1("html_export_delete_original_directory") ); if ( answer == KMessageBox::Yes ) { KIO::NetAccess::del( KURL(outputDir), MainView::theMainView() ); } else return false; } return true; } int HTMLExportDialog::calculateSteps() { int count = 0; for( QValueList::Iterator it2 = _cbs.begin(); it2 != _cbs.end(); ++it2 ) { if ( (*it2)->isChecked() ) count++; } return _list.count() * ( 1 + count ); // 1 thumbnail + 1 real image } QString HTMLExportDialog::namePage( int width, int height, const QString& fileName ) { QString name = _nameMap[fileName]; QString base = QFileInfo( name ).baseName(); return QString::fromLatin1( "%1-%2.html" ).arg( base ).arg( ImageSizeCheckBox::text(width,height,true) ); } QString HTMLExportDialog::nameImage( const QString& fileName, int size ) { QString name = _nameMap[fileName]; QString base = QFileInfo( name ).baseName(); QString ext = QFileInfo( name ).extension(); if ( size == _maxImageSize ) return name; else return QString::fromLatin1( "%1-%2.%3" ).arg( base ).arg( size ).arg( ext ); } bool HTMLExportDialog::linkIndexFile() { for( QValueList::Iterator it = _preferredSizes.begin(); it != _preferredSizes.end(); ++it ) { if ( (*it)->isChecked() ) { QString fromFile = QString::fromLatin1("index-%1.html" ) .arg((*it)->text(true)); QString destFile = _tempDir + QString::fromLatin1("/index.html"); bool ok = ( symlink( fromFile.latin1(), destFile.latin1() ) == 0 ); if ( !ok ) { KMessageBox::error( this, i18n("Unable to make a symlink from %1 to %2") .arg( fromFile ).arg( destFile ) ); return false; } return ok; } } return false; } QValueList HTMLExportDialog::activeResolutions() { QValueList res; for( QValueList::Iterator sizeIt = _cbs.begin(); sizeIt != _cbs.end(); ++sizeIt ) { if ( (*sizeIt)->isChecked() ) { res << *sizeIt; _maxImageSize = (*sizeIt)->width(); } } return res; } void HTMLExportDialog::populateThemesCombo() { QStringList dirs = KGlobal::dirs()->findDirs( "data", QString::fromLocal8Bit("kimdaba/themes/") ); int i = 0; for(QStringList::Iterator it = dirs.begin(); it != dirs.end(); ++it) { QDir dir(*it); QStringList themes = dir.entryList( QDir::Dirs | QDir::Readable ); for(QStringList::Iterator it = themes.begin(); it != themes.end(); ++it) { if(*it == QString::fromLatin1(".") || *it == QString::fromLatin1("..")) continue; QString themePath = QString::fromLatin1("%1/%2/").arg(dir.path()).arg(*it); KSimpleConfig themeConfig( QString::fromLatin1( "%1kimdaba.theme" ).arg( themePath ), true ); if( !themeConfig.hasGroup( QString::fromLatin1( "theme" ) ) ) { kdDebug() << QString::fromLatin1("invalid theme: %1 (missing theme section)").arg( *it ) << endl; continue; } themeConfig.setGroup( QString::fromLatin1( "theme" ) ); QString themeName = themeConfig.readEntry( "Name" ); QString themeAuthor = themeConfig.readEntry( "Author" ); enableButtonOK( true ); _themeBox->insertItem( i18n( "%1 (by %2)" ).arg( themeName ).arg( themeAuthor ), i ); _themes.insert( i, themePath ); i++; } } if(_themeBox->count() < 1) { KMessageBox::error( this, i18n("Could not find any themes - this is very likely an installation error" ) ); } } void HTMLExportDialog::getThemeInfo( QString* baseDir, QString* name, QString* author ) { *baseDir = _themes[_themeBox->currentItem()]; KSimpleConfig themeConfig( QString::fromLatin1( "%1kimdaba.theme" ).arg( *baseDir ), true ); themeConfig.setGroup( QString::fromLatin1( "theme" ) ); *name = themeConfig.readEntry( "Name" ); *author = themeConfig.readEntry( "Author" ); } int HTMLExportDialog::exec( const ImageInfoList& list ) { _list = list; return KDialogBase::exec(); } QString HTMLExportDialog::kimFileName( bool relative ) { if ( relative ) return QString::fromLatin1( "%2.kim" ).arg( _outputDir->text() ); else return QString::fromLatin1( "%1/%2.kim" ).arg( _tempDir ).arg( _outputDir->text() ); } #include "htmlexportdialog.moc"