/* ============================================================ * * This file is a part of kipi-plugins project * http://www.kipi-plugins.org * * Date : 2005-12-19 * Description : a plugin to export image collections using SimpleViewer. * * Copyright (C) 2005-2006 by Joern Ahrens * Copyright (C) 2008 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ // QT includes #include #include #include #include #include #include // KDE includes #include #include #include #include #include #include #include #include #include #include #include // KIPI includes #include #include #include // LibKDcraw includes. #include #include #if KDCRAW_VERSION < 0x000106 #include #endif // LibKExiv2 includes. #include // Local includes #include "pluginsversion.h" #include "firstrundlg.h" #include "svedialog.h" #include "simpleviewerexport.h" #include "simpleviewerexport.moc" namespace KIPISimpleViewerExportPlugin { // maxium size of a simpleviewer thumbnail // TODO: read from configfile const int maxThumbSize = 45; const TQString viewer("viewer.swf"); void SimpleViewerExport::run(KIPI::Interface* interface, TQObject *parent) { SimpleViewerExport *plugin = new SimpleViewerExport(interface, parent); if(!plugin->checkSimpleViewer()) { if(!plugin->installSimpleViewer()) { KMessageBox::error(TQT_TQWIDGET(kapp->activeWindow()), i18n("SimpleViewer installation failed")); return; } } if(plugin->configure()) plugin->startExport(); delete plugin; } SimpleViewerExport::SimpleViewerExport(KIPI::Interface* interface, TQObject *parent) : TQObject(parent) { m_interface = interface; m_configDlg = 0; m_totalActions = 0; m_action = 0; m_canceled = true; m_dataLocal = locateLocal("data", "kipiplugin_simpleviewerexport/simpleviewer/", true); m_tempDir = 0; m_simpleViewerFiles.append(viewer); m_simpleViewerFiles.append("swfobject.js"); const TDEAboutData *data = TDEApplication::kApplication()->aboutData(); m_hostName = TQString( data->appName() ); m_hostURL = data->homepage(); if (m_hostURL.isEmpty()) { m_hostName = "Kipi"; m_hostURL = "http://www.kipi-plugins.org"; } } SimpleViewerExport::~SimpleViewerExport() { if(m_tempDir) delete m_tempDir; } bool SimpleViewerExport::configure() { m_canceled = false; if(!m_configDlg) m_configDlg = new SVEDialog(m_interface, TQT_TQWIDGET(kapp->activeWindow())); bool configured = false; while(!configured) { if(m_configDlg->exec() == TQDialog::Rejected) return false; configured = true; if(TDEIO::NetAccess::exists(m_configDlg->exportURL(), false, TQT_TQWIDGET(kapp->activeWindow()))) { int ret = KMessageBox::warningYesNoCancel(TQT_TQWIDGET(kapp->activeWindow()), i18n("Target folder %1 already exists.\n" "Do you want to overwrite it (all data in this folder will be lost)") .arg(m_configDlg->exportURL())); switch(ret) { case KMessageBox::Yes: if(!TDEIO::NetAccess::del(m_configDlg->exportURL(), TQT_TQWIDGET(kapp->activeWindow()))) { KMessageBox::error(TQT_TQWIDGET(kapp->activeWindow()), i18n("Could not delete %1\n" "Please choose another export folder").arg(m_configDlg->exportURL())); configured = false; } break; case KMessageBox::No: configured = false; break; case KMessageBox::Cancel: return false; break; }; } } return true; } void SimpleViewerExport::startExport() { if(m_canceled) return; m_progressDlg = new KIPI::BatchProgressDialog(TQT_TQWIDGET(kapp->activeWindow()), i18n("Flash Export")); connect(m_progressDlg, TQT_SIGNAL(cancelClicked()), this, TQT_SLOT(slotCancel())); m_progressDlg->show(); kapp->processEvents(); // Estimate the number of actions for the KIPI progress dialog. m_progressDlg->addedAction(i18n("Estimate the number of actions to do..."), KIPI::StartingMessage); m_albumsList = m_configDlg->getSelectedAlbums(); m_totalActions = 0; for( TQValueList::Iterator it = m_albumsList.begin() ; !m_canceled && (it != m_albumsList.end()) ; ++it ) { m_totalActions += (*it).images().count(); } // +copying SimpleViewer, +creating index.html m_totalActions += 2; m_progressDlg->setProgress(0, m_totalActions); slotProcess(); #if TDE_VERSION >= 0x30200 m_progressDlg->setButtonCancel(KStdGuiItem::close()); #else m_progressDlg->setButtonCancelText(i18n("&Close")); #endif } void SimpleViewerExport::slotCancel() { m_progressDlg->addedAction(i18n("Export canceled"), KIPI::ErrorMessage); m_canceled = true; } void SimpleViewerExport::slotProcess() { if(m_canceled) return; m_progressDlg->addedAction(i18n("Initialising..."), KIPI::StartingMessage); if(!m_canceled && !createExportDirectories()) { m_progressDlg->addedAction(i18n("Failed to create export directories"), KIPI::ErrorMessage); return; } if(!m_canceled && !exportImages()) { m_progressDlg->addedAction(i18n("Failed to export the images"), KIPI::ErrorMessage); return; } if(!m_canceled && !createIndex()) { m_progressDlg->addedAction(i18n("Failed to create index.html"), KIPI::ErrorMessage); return; } if(!m_canceled && !copySimpleViewer()) { m_progressDlg->addedAction(i18n("Failed to copy SimpleViewer files"), KIPI::ErrorMessage); return; } if(!m_canceled && !upload()) { m_progressDlg->addedAction(i18n("Failed to upload the gallery"), KIPI::ErrorMessage); return; } if(m_canceled) { int ret = KMessageBox::warningYesNo(TQT_TQWIDGET(kapp->activeWindow()), i18n("Export was canceled.\n" "Do you want to delete the yet created files in %1 ?") .arg(m_configDlg->exportURL())); if(ret == KMessageBox::Yes) { TDEIO::NetAccess::del(m_configDlg->exportURL(), TQT_TQWIDGET(kapp->activeWindow())); } } if(!m_canceled) m_progressDlg->addedAction(i18n("Finished..."), KIPI::SuccessMessage); } bool SimpleViewerExport::createExportDirectories() { m_tempDir = new KTempDir(locateLocal("tmp", "simpleviewerexport")); m_tempDir->setAutoDelete(true); m_progressDlg->addedAction(i18n("Creating directories..."), KIPI::StartingMessage); KURL root = m_configDlg->exportURL(); if(!TDEIO::NetAccess::mkdir(root, TQT_TQWIDGET(kapp->activeWindow()))) { m_progressDlg->addedAction(i18n("Could not create folder '%1'").arg(root.url()), KIPI::ErrorMessage); return(false); } KURL thumbsDir = m_tempDir->name(); thumbsDir.addPath("/thumbs"); if(!TDEIO::NetAccess::mkdir(thumbsDir, TQT_TQWIDGET(kapp->activeWindow()))) { m_progressDlg->addedAction(i18n("Could not create folder '%1'").arg(thumbsDir.url()), KIPI::ErrorMessage); return(false); } KURL imagesDir = m_tempDir->name(); imagesDir.addPath("/images"); if(!TDEIO::NetAccess::mkdir(imagesDir, TQT_TQWIDGET(kapp->activeWindow()))) { m_progressDlg->addedAction(i18n("Could not create folder '%1'").arg(imagesDir.url()), KIPI::ErrorMessage); return(false); } m_progressDlg->setProgress(++m_action, m_totalActions); m_progressDlg->addedAction(i18n("Directories created..."), KIPI::SuccessMessage); return true; } bool SimpleViewerExport::exportImages() { if(m_canceled) return false; m_progressDlg->addedAction(i18n("Creating images and thumbnails..."), KIPI::StartingMessage); KURL thumbsDir(m_tempDir->name()); thumbsDir.addPath("/thumbs"); KURL imagesDir(m_tempDir->name()); imagesDir.addPath("/images"); KURL xmlFile(m_tempDir->name()); xmlFile.addPath("/gallery.xml"); TQFile file(xmlFile.path()); file.open(IO_WriteOnly); TQDomDocument xmlDoc; xmlDoc.appendChild(xmlDoc.createProcessingInstruction( TQString::fromLatin1("xml"), TQString::fromLatin1("version=\"1.0\" encoding=\"UTF-8\"") ) ); TQDomElement galleryElem = xmlDoc.createElement(TQString::fromLatin1("simpleviewerGallery")); xmlDoc.appendChild( galleryElem ); galleryElem.setAttribute(TQString::fromLatin1("maxImageWidth"), m_configDlg->maxImageDimension()); galleryElem.setAttribute(TQString::fromLatin1("maxImageHeight"), m_configDlg->maxImageDimension()); galleryElem.setAttribute(TQString::fromLatin1("textColor"), TQString(m_configDlg->textColor().name()).replace("#", "0x")); galleryElem.setAttribute(TQString::fromLatin1("frameColor"), TQString(m_configDlg->frameColor().name()).replace("#", "0x")); galleryElem.setAttribute(TQString::fromLatin1("bgColor"), TQString(m_configDlg->backgroundColor().name()).replace("#", "0x")); galleryElem.setAttribute(TQString::fromLatin1("frameWidth"), m_configDlg->frameWidth()); galleryElem.setAttribute(TQString::fromLatin1("stagePadding"), m_configDlg->stagePadding()); galleryElem.setAttribute(TQString::fromLatin1("thumbnailColumns"), m_configDlg->thumbnailColumns()); galleryElem.setAttribute(TQString::fromLatin1("thumbnailRows"), m_configDlg->thumbnailRows()); galleryElem.setAttribute(TQString::fromLatin1("navPosition"), m_configDlg->navPosition()); galleryElem.setAttribute(TQString::fromLatin1("navDirection"), m_configDlg->navDirection()); galleryElem.setAttribute(TQString::fromLatin1("title"), m_configDlg->title()); galleryElem.setAttribute(TQString::fromLatin1("imagePath"), TQString()); galleryElem.setAttribute(TQString::fromLatin1("thumbPath"), TQString()); KExiv2Iface::KExiv2 meta; TQImage image; TQImage thumbnail; TQString tmp; TQString newName; int index = 1; int maxSize = m_configDlg->imagesExportSize(); bool resizeImages = m_configDlg->resizeExportImages(); for( TQValueList::Iterator it = m_albumsList.begin() ; !m_canceled && (it != m_albumsList.end()) ; ++it ) { KURL::List images = (*it).images(); for(KURL::List::Iterator it = images.begin(); !m_canceled && (it != images.end()) ; ++it) { kapp->processEvents(); KURL url = *it; TQFileInfo fileInfo(url.path()); m_progressDlg->addedAction(i18n("Processing %1").arg(url.filename()), KIPI::StartingMessage); // Check if RAW file. #if KDCRAW_VERSION < 0x000106 TQString rawFilesExt(KDcrawIface::DcrawBinary::instance()->rawFiles()); #else TQString rawFilesExt(KDcrawIface::KDcraw::rawFiles()); #endif if (rawFilesExt.upper().contains( fileInfo.extension(false).upper() )) KDcrawIface::KDcraw::loadDcrawPreview(image, url.path()); else image.load(url.path()); if(image.isNull()) { m_progressDlg->addedAction(i18n("Could not open image '%1'").arg(url.filename()), KIPI::WarningMessage); continue; } if(!createThumbnail(image, thumbnail)) { m_progressDlg->addedAction(i18n("Could not create thumbnail from '%1'").arg(url.filename()), KIPI::WarningMessage); continue; } if(resizeImages && !resizeImage(image, maxSize, image)) { m_progressDlg->addedAction(i18n("Could not resize image '%1'").arg(url.filename()), KIPI::WarningMessage); continue; } meta.load(url.path()); newName = TQString("%1.%2").arg(tmp.sprintf("%03i", index)).arg(TQString("jpg")); KURL thumbnailPath(thumbsDir); thumbnailPath.addPath(newName); thumbnail.save(thumbnailPath.path(), "JPEG"); KURL imagePath(imagesDir); imagePath.addPath(newName); image.save(imagePath.path(), "JPEG"); // Backup metadata from original image. meta.setImageProgramId(TQString("Kipi-plugins"), TQString(kipiplugins_version)); meta.setImageDimensions(image.size()); meta.save(imagePath.path()); cfgAddImage(xmlDoc, galleryElem, url, newName); m_progressDlg->setProgress(++m_action, m_totalActions); index++; } } TQCString data(xmlDoc.toCString()); TQDataStream stream( &file ); stream.writeRawBytes(data.data(), data.size()); file.close(); m_progressDlg->addedAction(i18n("Images and thumbnails created..."), KIPI::SuccessMessage); return true; } bool SimpleViewerExport::createThumbnail(const TQImage &image, TQImage &thumbnail) { int w = image.width(); int h = image.height(); int maxSize; if(w > maxThumbSize || h > maxThumbSize) { if(w > h) { maxSize = (int)(double)(w * maxThumbSize) / h; } else { maxSize = (int)(double)(h * maxThumbSize) / w; } } maxSize = (maxSize < maxThumbSize) ? maxThumbSize : maxSize; return resizeImage(image, maxSize, thumbnail); } bool SimpleViewerExport::resizeImage(const TQImage &image, int maxSize, TQImage &resizedImage) { int w = image.width(); int h = image.height(); if(w > maxSize || h > maxSize) { if(w > h) { h = (int)(double)(h * maxSize) / w; h = (h == 0) ? 1 : h; w = maxSize; } else { w = (int)(double)(w * maxSize) / h; w = (w == 0) ? 1 : w; h = maxSize; } resizedImage = image.smoothScale(w, h); } return true; } void SimpleViewerExport::cfgAddImage(TQDomDocument &xmlDoc, TQDomElement &galleryElem, const KURL &url, const TQString& newName) { if(m_canceled) return; TQString comment; if(m_configDlg->showExifComments()) { KIPI::ImageInfo info = m_interface->info(url); comment = info.description(); } else { comment = TQString(); } TQDomElement img = xmlDoc.createElement(TQString::fromLatin1("image")); galleryElem.appendChild(img); TQDomElement name = xmlDoc.createElement(TQString::fromLatin1("name")); img.appendChild(name); TQDomText nametxt = xmlDoc.createTextNode(newName); name.appendChild(nametxt); TQDomElement caption = xmlDoc.createElement(TQString::fromLatin1("caption")); img.appendChild(caption); TQDomText captiontxt = xmlDoc.createTextNode(comment); caption.appendChild(captiontxt); } bool SimpleViewerExport::createIndex() { if(m_canceled) return false; m_progressDlg->addedAction(i18n("Creating index.html..."), KIPI::StartingMessage); TQString indexTemplateName = locate("data", "kipiplugin_simpleviewerexport/index.template"); if(indexTemplateName.isEmpty()) { //TODO: errormsg kdDebug() << "No indexTemplateName" << endl; return false; } TQFile infile(indexTemplateName); infile.open(IO_ReadOnly); TQTextStream in(&infile); TQString indexTemplate = in.read(); infile.close(); indexTemplate.replace("{TITLE}", m_configDlg->title()); indexTemplate.replace("{COLOR}", m_configDlg->textColor().name()); indexTemplate.replace("{BGCOLOR}", m_configDlg->backgroundColor().name()); indexTemplate.replace("{HOSTURL}", m_hostURL); indexTemplate.replace("{HOSTNAME}", m_hostName); TQFile outfile(m_tempDir->name() + "/index.html"); outfile.open(IO_WriteOnly); TQTextStream out(&outfile); out << indexTemplate; outfile.close(); m_progressDlg->setProgress(++m_action, m_totalActions); m_progressDlg->addedAction(i18n("index.html created..."), KIPI::SuccessMessage); return true; } bool SimpleViewerExport::copySimpleViewer() { if(m_canceled) return false; m_progressDlg->addedAction(i18n("Copying flash files..."), KIPI::StartingMessage); TQString dataDir; // Due to its license, simpleviewer is installed in $TDEHOME dataDir = locate("data", "kipiplugin_simpleviewerexport/simpleviewer/"); if(dataDir.isEmpty()) installSimpleViewer(); if(dataDir.isEmpty()) return false; TQStringList files; TQStringList entries; TQDir dir; dir.setPath(dataDir); entries = dir.entryList(TQDir::Files); for(TQStringList::Iterator it = entries.begin(); it != entries.end(); ++it) { files.append(dir.absPath() + "/" + *it); } // files distributed with the plugin are installed in $TDEDIRS dataDir = locate("data", "kipiplugin_simpleviewerexport/simpleviewer_html/"); dir.setPath(dataDir); entries = dir.entryList(TQDir::Files); for(TQStringList::Iterator it = entries.begin(); it != entries.end(); ++it) { files.append(dir.absPath() + "/" + *it); } // TODO: catch errors TDEIO::CopyJob *copyJob = TDEIO::copy(files, m_configDlg->exportURL(), true); m_progressDlg->addedAction(i18n("flash files copied..."), KIPI::SuccessMessage); return true; } bool SimpleViewerExport::upload() { if(m_canceled) return false; m_progressDlg->addedAction(i18n("Uploading gallery..."), KIPI::StartingMessage); if(!TDEIO::NetAccess::dircopy(m_tempDir->name() + "./", m_configDlg->exportURL(), 0)) return false; m_progressDlg->addedAction(i18n("Gallery uploaded..."), KIPI::SuccessMessage); return true; } bool SimpleViewerExport::checkSimpleViewer() const { return ! locate("data", "kipiplugin_simpleviewerexport/simpleviewer/"+viewer).isEmpty(); } bool SimpleViewerExport::installSimpleViewer() { FirstRunDlg *firstRunDlg = new FirstRunDlg(TQT_TQWIDGET(kapp->activeWindow())); if(firstRunDlg->exec() == TQDialog::Accepted) { TQString url = firstRunDlg->getURL(); delete firstRunDlg; if(unzip(url)) { return true; } else { // ErrorMessage } } return false; } bool SimpleViewerExport::unzip(const TQString &url) { KZip zip(url); if(!openArchive(zip)) { return false; } return extractArchive(zip); } bool SimpleViewerExport::openArchive(KZip &zip) { if(!zip.open(IO_ReadOnly)) { kdDebug() << "open archive failed\n"; return false; } return true; } bool SimpleViewerExport::extractArchive(KZip &zip) { // read root directory content TQStringList names = zip.directory()->entries(); if(names.count() != 1) { kdDebug() << "Wrong SimpleViewer Version or corrupted archive" << endl; kdDebug() << "Content of the archive root folder" << names << endl; return false; } // open root directory const KArchiveEntry *root = zip.directory()->entry(names[0]); if(!root || !root->isDirectory()) { kdDebug() << "could not open " << names[0] << " of zipname" << endl; return false; } const KArchiveDirectory *dir = dynamic_cast(root); // extract the needed files from SimpleViewer archive for(TQStringList::Iterator it = m_simpleViewerFiles.begin(); it != m_simpleViewerFiles.end(); ++it ) { const KArchiveEntry *entry = dir->entry(*it); if(!extractFile(entry)) { //TODO error msg kdDebug() << "could not open " << *it << " of zipname" << endl; return false; } } return true; } bool SimpleViewerExport::extractFile(const KArchiveEntry *entry) { if( !entry || !entry->isFile() ) return false; const KArchiveFile *entryFile = dynamic_cast(entry); TQByteArray array = entryFile->data(); TQFile file( m_dataLocal + entry->name() ); if(file.open( IO_WriteOnly )) { int ret = file.writeBlock(array); file.close(); return ret > 0 ? true : false; } return false; } } // namespace KIPISimpleViewerExportPlugin