1 /* Copyright (C) 2003-2006 Jesper K. Pedersen <blackie@kde.org>
3 This program is free software; you can redistribute it and/or
4 modify it under the terms of the GNU General Public
5 License as published by the Free Software Foundation; either
6 version 2 of the License, or (at your option) any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; see the file COPYING. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
20 #include <kfiledialog.h>
22 #include <qfileinfo.h>
24 #include "Utilities/Util.h"
25 #include <q3progressdialog.h>
28 #include "ImageManager/Manager.h"
29 #include "DB/ImageInfo.h"
30 #include "DB/ResultId.h"
31 #include <qapplication.h>
32 #include <kmessagebox.h>
34 #include <qcheckbox.h>
37 #include <qradiobutton.h>
39 #include "XMLHandler.h"
40 #include <QVBoxLayout>
43 using namespace ImportExport
;
45 void Export::imageExport(const DB::Result
& list
)
48 if ( config
.exec() == QDialog::Rejected
)
52 if ( config
._enforeMaxSize
->isChecked() )
53 maxSize
= config
._maxSize
->value();
55 // Ask for zip file name
56 QString zipFile
= KFileDialog::getSaveFileName( KUrl(), QString::fromLatin1( "*.kim|KPhotoAlbum Export Files" ) );
57 if ( zipFile
.isNull() )
61 Export
* exp
= new Export( list
, zipFile
, config
._compress
->isChecked(), maxSize
, config
.imageFileLocation(),
62 QString::fromLatin1( "" ), config
._generateThumbnails
->isChecked(), &ok
);
63 delete exp
; // It will not return before done - we still need a class to connect slots etc.
69 // PENDING(blackie) add warning if images are to be copied into a non empty directory.
70 ExportConfig::ExportConfig()
72 setWindowTitle( i18n("Export Configuration / Copy Images") );
73 setButtons( KDialog::Ok
| KDialog::Cancel
| KDialog::Help
);
74 QWidget
* top
= new QWidget
;
77 QVBoxLayout
* lay1
= new QVBoxLayout( top
);
80 QGroupBox
* grp
= new QGroupBox( i18n("How to Handle Images") );
81 lay1
->addWidget( grp
);
83 QVBoxLayout
* boxLay
= new QVBoxLayout( grp
);
84 _include
= new QRadioButton( i18n("Include in .kim file"), grp
);
85 _manually
= new QRadioButton( i18n("Manual copy next to .kim file"), grp
);
86 _auto
= new QRadioButton( i18n("Automatically copy next to .kim file"), grp
);
87 _link
= new QRadioButton( i18n("Hard link next to .kim file"), grp
);
88 _manually
->setChecked( true );
90 boxLay
->addWidget( _include
);
91 boxLay
->addWidget( _manually
);
92 boxLay
->addWidget( _auto
);
93 boxLay
->addWidget( _link
);
96 _compress
= new QCheckBox( i18n("Compress export file"), top
);
97 lay1
->addWidget( _compress
);
99 // Generate thumbnails
100 _generateThumbnails
= new QCheckBox( i18n("Generate thumbnails"), top
);
101 _generateThumbnails
->setChecked(true);
102 lay1
->addWidget( _generateThumbnails
);
105 QHBoxLayout
* hlay
= new QHBoxLayout
;
106 lay1
->addLayout( hlay
);
108 _enforeMaxSize
= new QCheckBox( i18n( "Limit maximum image dimensions to: " ) );
109 hlay
->addWidget( _enforeMaxSize
);
111 _maxSize
= new QSpinBox
;
112 _maxSize
->setRange( 100,4000 );
114 hlay
->addWidget( _maxSize
);
115 _maxSize
->setValue( 800 );
117 connect( _enforeMaxSize
, SIGNAL( toggled( bool ) ), _maxSize
, SLOT( setEnabled( bool ) ) );
118 _maxSize
->setEnabled( false );
120 QString txt
= i18n( "<p>If your images are stored in a non-compressed file format then you may check this; "
121 "otherwise, this just wastes time during import and export operations.</p>"
122 "<p>In other words, do not check this if your images are stored in jpg, png or gif; but do check this "
123 "if your images are stored in tiff.</p>" );
124 _compress
->setWhatsThis( txt
);
126 txt
= i18n( "<p>Generate thumbnail images</p>" );
127 _generateThumbnails
->setWhatsThis( txt
);
129 txt
= i18n( "<p>With this option you may limit the maximum dimensions (width and height) of your images. "
130 "Doing so will make the resulting export file smaller, but will of course also make the quality "
131 "worse if someone wants to see the exported images with larger dimensions.</p>" );
133 _enforeMaxSize
->setWhatsThis( txt
);
134 _maxSize
->setWhatsThis( txt
);
136 txt
= i18n("<p>When exporting images, bear in mind that there are two things the "
137 "person importing these images again will need:<br/>"
138 "1) meta information (image content, date etc.)<br/>"
139 "2) the images themselves.</p>"
141 "<p>The images themselves can either be placed next to the .kim file, "
142 "or copied into the .kim file. Copying the images into the .kim file works well "
143 "for a recipient who wants all, or most of those images, for example "
144 "when emailing a whole group of images. However, when you place the "
145 "images on the Web, a lot of people will see them but most likely only "
146 "download a few of them. It works better in this kind of case, to "
147 "separate the images and the .kim file, by place them next to each "
148 "other, so the user can access the images s/he wants.</p>");
150 grp
->setWhatsThis( txt
);
151 _include
->setWhatsThis( txt
);
152 _manually
->setWhatsThis( txt
);
153 _link
->setWhatsThis( txt
);
154 _auto
->setWhatsThis( txt
);
155 setHelp( QString::fromLatin1( "chp-exportDialog" ) );
158 ImageFileLocation
ExportConfig::imageFileLocation() const
160 if ( _include
->isChecked() )
162 else if ( _manually
->isChecked() )
164 else if ( _link
->isChecked() )
172 const DB::Result
& list
,
173 const QString
& zipFile
,
176 ImageFileLocation location
,
177 const QString
& baseUrl
,
178 bool doGenerateThumbnails
,
181 , _maxSize( maxSize
)
182 , _location( location
)
185 _destdir
= QFileInfo( zipFile
).path();
186 _zip
= new KZip( zipFile
);
187 _zip
->setCompression( compress
? KZip::DeflateCompression
: KZip::NoCompression
);
188 if ( ! _zip
->open( QIODevice::WriteOnly
) ) {
189 KMessageBox::error( 0, i18n("Error creating zip file") );
194 // Create progress dialog
196 if (location
!= ManualCopy
)
197 total
+= list
.size();
198 if (doGenerateThumbnails
)
199 total
+= list
.size();
202 _progressDialog
= new Q3ProgressDialog( QString(), i18n("&Cancel"), total
, 0, "progress dialog", true );
203 _progressDialog
->setProgress( 0 );
204 _progressDialog
->show();
206 // Copy image files and generate thumbnails
207 if ( location
!= ManualCopy
) {
208 _copyingFiles
= true;
212 if ( _ok
&& doGenerateThumbnails
) {
213 _copyingFiles
= false;
214 generateThumbnails( list
);
218 // Create the index.xml file
219 _progressDialog
->setLabelText(i18n("Creating index file"));
220 Q3CString indexml
= XMLHandler().createIndexXML( list
, baseUrl
, _location
, &_filenameMapper
);
223 _zip
->writeFile( QString::fromLatin1( "index.xml" ), QString(), QString(), indexml
.data(), indexml
.size()-1 );
226 _progressDialog
->setProgress( _steps
);
232 void Export::generateThumbnails(const DB::Result
& list
)
234 _progressDialog
->setLabelText( i18n("Creating thumbnails") );
235 _loopEntered
= false;
236 _subdir
= QString::fromLatin1( "Thumbnails/" );
237 _filesRemaining
= list
.size(); // Used to break the event loop.
238 Q_FOREACH(const DB::ImageInfoPtr info
, list
.fetchInfos()) {
239 ImageManager::ImageRequest
* request
= new ImageManager::ImageRequest( info
->fileName(DB::AbsolutePath
), QSize( 128, 128 ), info
->angle(), this );
240 request
->setPriority( ImageManager::BatchTask
);
241 ImageManager::Manager::instance()->load( request
);
243 if ( _filesRemaining
> 0 ) {
249 void Export::copyImages(const DB::Result
& list
)
251 Q_ASSERT( _location
!= ManualCopy
);
253 _loopEntered
= false;
254 _subdir
= QString::fromLatin1( "Images/" );
256 _progressDialog
->setLabelText( i18n("Copying image files") );
259 Q_FOREACH(const DB::ImageInfoPtr info
, list
.fetchInfos()) {
260 QString file
= info
->fileName(DB::AbsolutePath
);
261 QString zippedName
= _filenameMapper
.uniqNameFor(file
);
263 if ( _maxSize
== -1 || Utilities::isVideo( file
) ) {
264 if ( QFileInfo( file
).isSymLink() )
265 file
= QFileInfo(file
).readLink();
267 if ( _location
== Inline
)
268 _zip
->addLocalFile( file
, QString::fromLatin1( "Images/" ) + zippedName
);
269 else if ( _location
== AutoCopy
)
270 Utilities::copy( file
, _destdir
+ QString::fromLatin1( "/" ) + zippedName
);
271 else if ( _location
== Link
)
272 Utilities::makeHardLink( file
, _destdir
+ QString::fromLatin1( "/" ) + zippedName
);
275 _progressDialog
->setProgress( _steps
);
279 ImageManager::ImageRequest
* request
=
280 new ImageManager::ImageRequest( file
, QSize( _maxSize
, _maxSize
), 0, this );
281 request
->setPriority( ImageManager::BatchTask
);
282 ImageManager::Manager::instance()->load( request
);
285 // Test if the cancel button was pressed.
286 qApp
->processEvents( QEventLoop::AllEvents
);
288 if ( _progressDialog
->wasCanceled() ) {
293 if ( _filesRemaining
> 0 ) {
299 void Export::pixmapLoaded( const QString
& fileName
, const QSize
& /*size*/, const QSize
& /*fullSize*/, int /*angle*/, const QImage
& image
, const bool loadedOK
)
304 const QString ext
= Utilities::isVideo( fileName
) ? QString::fromLatin1( "jpg" ) : QFileInfo( _filenameMapper
.uniqNameFor(fileName
) ).completeSuffix();
306 // Add the file to the zip archive
307 QString zipFileName
= QString::fromLatin1( "%1/%2.%3" ).arg( Utilities::stripSlash(_subdir
))
308 .arg(QFileInfo( _filenameMapper
.uniqNameFor(fileName
) ).baseName()).arg( ext
);
310 QBuffer
buffer( &data
);
311 buffer
.open( QIODevice::WriteOnly
);
312 image
.save( &buffer
, QFileInfo(zipFileName
).suffix().toLower().toLatin1() );
314 if ( _location
== Inline
|| !_copyingFiles
)
315 _zip
->writeFile( zipFileName
, QString(), QString(), data
, data
.size() );
317 QString file
= _destdir
+ QString::fromLatin1( "/" ) + _filenameMapper
.uniqNameFor(fileName
);
319 if ( !out
.open( QIODevice::WriteOnly
) ) {
320 KMessageBox::error( 0, i18n("Error writing file %1", file
) );
323 out
.write( data
, data
.size() );
327 qApp
->processEvents( QEventLoop::AllEvents
);
329 bool canceled
= (!_ok
|| _progressDialog
->wasCanceled());
334 ImageManager::Manager::instance()->stop( this );
340 _progressDialog
->setProgress( _steps
);
343 if ( _filesRemaining
== 0 && _loopEntered
)
347 void Export::showUsageDialog()
350 i18n( "<p>Other KPhotoAlbum users may now load the import file into their database, by choosing <b>import</b> in "
352 "<p>If they find it on a web site, and the web server is correctly configured, all they need to do is simply "
353 "to click it from within konqueror. To enable this, your web server needs to be configured for KPhotoAlbum. You do so by adding "
354 "the following line to <b>/etc/httpd/mime.types</b> or similar:"
355 "<pre>application/vnd.kde.kphotoalbum-import kim</pre>"
356 "This will make your web server tell konqueror that it is a KPhotoAlbum file when clicking on the link, "
357 "otherwise the web server will just tell konqueror that it is a plain text file.</p>" );
359 KMessageBox::information( 0, txt
, i18n("How to Use the Export File"), QString::fromLatin1("export_how_to_use_the_export_file") );
365 #include "Export.moc"