AlbumShaper 1.0a3
addPhotosDialog.cpp
Go to the documentation of this file.
1//==============================================
2// copyright : (C) 2003-2005 by Will Stokes
3//==============================================
4// This program is free software; you can redistribute it
5// and/or modify it under the terms of the GNU General
6// Public License as published by the Free Software
7// Foundation; either version 2 of the License, or
8// (at your option) any later version.
9//==============================================
10
11//Systemwide includes
12#include <qlabel.h>
13#include <q3filedialog.h>
14#include <qcheckbox.h>
15#include <qlayout.h>
16#include <qpixmap.h>
17#include <qimage.h>
18#include <qlayout.h>
19#include <qfileinfo.h>
20#include <qmutex.h>
21#include <qthread.h>
22#include <qevent.h>
23#include <qapplication.h>
24//Added by qt3to4:
25#include <Q3GridLayout>
26#include <QCustomEvent>
27
28//Projectwide includes
29#include "addPhotosDialog.h"
30#include "../../config.h"
32
33#define MIN_WIDTH 240
34#define MIN_HEIGHT 180
35
36#define UPDATE_PREVIEW_DETAILS QEvent::User
37
38//================================
39//Qt requires us to pass information for GUI posting from the worker thread to the
40//GUI thread via events as opposed to directly posting the events ourselves. in order
41//to update the file preview we'll construct custom UpdatePreviewEvents that contain
42//the updated preview image and file details.
44{
45public:
47 {
48 this->image = image;
49 this->details = details;
50 }
51
52 //returns the preview image
53 QImage getImage() const { return image; }
54
55 //returns the file details string
56 QString getDetails() const { return details; }
57
58private:
59 QImage image;
60 QString details;
61};
62//================================
64{
65 //we'll need to store a previewWidget handle to
66 //posting update events when updates are
67 //ready to be shown
68 this->previewWidget = previewWidget;
69
70 //by default worker thread isn't busy yet
71 updating = false;
72 queue = QString::null;
73}
74//================================
75void GeneratePreviewThread::start( QString filename )
76{
77 //get lock
78 lockingMutex.lock();
79
80 //if currently animating then append job to queue
81 if(updating)
82 {
84 lockingMutex.unlock();
85 return;
86 }
87 //else set animating to true, actually initiate job
88 else
89 {
90 updating = true;
91 this->filename = filename;
92 lockingMutex.unlock();
93 QThread::start();
94 }
95}
96//================================
98{
99 //since it is possible for another job
100 //to be added to the queue while processing this one, it is necessary
101 //to loop until the queue is empty
102 while(true)
103 {
104 //------------------------------------------
105 //Get image type extension and convert to caps
106 QString extension = QFileInfo(filename).extension(false).upper();
107 bool validExtension = ( (extension.compare("GIF") == 0) ||
108 (extension.compare("JPG") == 0) ||
109 (extension.compare("JPEG") == 0) ||
110 (extension.compare("PNG") == 0) ||
111 (extension.compare("XPM") == 0) );
112 //------------------------------------------
113 //Scale the image to fit nicely on the screen, aka < 300x225
114 QImage scaledImage;
115 if( validExtension )
116 {
117 scaleImage(filename, scaledImage, MIN_WIDTH, MIN_HEIGHT );
118 }
119 //------------------------------------------
120 //Get image resolution
121 QString imageRes = "";
122 if(validExtension)
123 {
124 QSize res;
125 getImageSize( filename, res );
126 imageRes = QString("%1 x %2").arg(res.width()).arg(res.height());
127 }
128 //------------------------------------------
129 //Determine file size and construct a nicely formatted size string
130 QString fileSize = "?";
131 QFileInfo info;
132 info.setFile( filename );
133 int sizeOnDisk = info.size();
134
135 if(sizeOnDisk < 1024)
136 fileSize = QString("%1 Byte%2").arg(sizeOnDisk).arg( sizeOnDisk == 0 || sizeOnDisk > 1 ? "s" : "");
137 else if( sizeOnDisk/1024 < 1024)
138 // fileSize = QString("%1 Kb").arg( ((float)*sizeOnDisk)/1024 );
139 fileSize = QString("%1 Kb").arg( ((float)((100*sizeOnDisk)/1024))/100 );
140 else if( sizeOnDisk/(1024*1024) < 1024)
141 fileSize = QString("%1 Mb").arg( ((float)((100*sizeOnDisk)/(1024*1024)))/100 );
142 else
143 fileSize = QString("%1 Gigs").arg( ((float)((100*sizeOnDisk)/(1024*1024*1024)))/100 );
144 //------------------------------------------
145 //Setup image details string
146 QString fileDetails = QString("%1 %2, %3")
147 .arg(imageRes)
148 .arg(extension)
149 .arg(fileSize);
150 //------------------------------------------
151 //Post UPDATE_PREVIEW_DETAILS event
152 UpdatePreviewEvent* upe = new UpdatePreviewEvent( scaledImage, fileDetails );
153 QApplication::postEvent( previewWidget, upe );
154 //------------------------------------------
155 //get lock
156 lockingMutex.lock();
157
158 //if the queue is empty we're done!
159 if( queue.isNull() )
160 {
161 updating = false;
162 lockingMutex.unlock();
163 return;
164 }
165 //clear queue and process pending job
166 else
167 {
168 filename = queue;
169 queue = QString::null;
170 lockingMutex.unlock();
171 }
172
173 } //end while(true)
174}
175//================================
177{
178 //create widgets for display preview image and details
179 filePreview = new QLabel( this );
180 fileDetails = new QLabel( this );
181
182 Q3GridLayout* grid = new Q3GridLayout( this, 4, 3 );
183 grid->setRowStretch( 0, 1 );
184 grid->addWidget( filePreview, 1, 1, Qt::AlignHCenter );
185 grid->addWidget( fileDetails, 2, 1, Qt::AlignHCenter );
186 grid->setRowStretch( 3, 1 );
187
188 grid->setColStretch( 0, 1 );
189 grid->setColStretch( 2, 1 );
190
191 //create a generator thread that will be used for actually generating
192 //preview images and constructing details strings
194}
195//==============================================
197{
198 //make sure generator thread is done!
199 generatorThread->wait();
200 delete generatorThread;
201 generatorThread = NULL;
202}
203//==============================================
205{
206 QFontMetrics fm( font() );
207 return QSize(MIN_WIDTH, MIN_HEIGHT + 2*fm.height() );
208}
209//==============================================
211{
212 //handle UpdatePrevewEvents that are sent from the worker thread
213 //by update the preview image and details that are shown
214 if ( e->type() == UPDATE_PREVIEW_DETAILS )
215 {
217
218 if( !upe->getImage().isNull() )
219 {
220 QPixmap scaledPixmap;
221 scaledPixmap.convertFromImage( upe->getImage() );
222 filePreview->setPixmap( scaledPixmap );
223 }
224
225 fileDetails->setText( upe->getDetails() );
226 }
227}
228//==============================================
229void FilePreview::updatePreview( const QString& filename )
230{
231 //handle requests to update the preview information by asking
232 //the generator thread to handle them. by using
233 //an auxiallary thread we can process requests very quickly while
234 //any current work being done to generate an image preview continues
235 if( generatorThread != NULL)
236 {
237 generatorThread->start( filename );
238 }
239}
240//==============================================
241AddPhotosDialog::AddPhotosDialog(QString path, QWidget *parent, const char* name ) :
242 Q3FileDialog(path,
243 tr("Images") + " (*.gif *.jpg *.jpeg *.png *.xpm *.GIF *.JPG *.JPEG *.PNG *.XPM)",
244 parent,name)
245 {
246 //setup filter filter and modes
247 setMode( Q3FileDialog::ExistingFiles );
248 setViewMode( Q3FileDialog::List );
249
250 filePreview = new FilePreview();
251 setContentsPreviewEnabled( true );
252 setContentsPreview( filePreview, filePreview );
253 setPreviewMode( Q3FileDialog::Contents );
254
255 //create label and checkbox asking user if they want to
256 //set image descriptions from filenames
257 setDescriptions = new QCheckBox( tr("Use filenames for descriptions."), this );
258 setDescriptions->setChecked( false );
259 addWidgets( NULL, setDescriptions, NULL );
260
261 //set window description
262 setCaption( tr("Add Photos") );
263
264 connect( this, SIGNAL( fileHighlighted(const QString&)),
265 this, SLOT( updatePreview(const QString&)) );
266}
267//==============================================
268QStringList AddPhotosDialog::getFilenames(bool& setDescriptionsBool)
269{
270 if( exec() == QDialog::Accepted )
271 {
272 setDescriptionsBool = setDescriptions->isChecked();
273 return selectedFiles();
274 }
275 else { return QStringList(); }
276}
277//==============================================
278void AddPhotosDialog::updatePreview(const QString& filename)
279{
280 filePreview->updatePreview( filename );
281}
282//==============================================
#define MIN_HEIGHT
#define UPDATE_PREVIEW_DETAILS
#define MIN_WIDTH
FilePreview * filePreview
Used to preview selected files.
AddPhotosDialog(QString path, QWidget *parent=0, const char *name=0)
QCheckBox * setDescriptions
Checkbox asking if filenames should be used to set image descriptions.
void updatePreview(const QString &filename)
handle the user selecting items by updating the file preview fields
QStringList getFilenames(bool &setDescriptions)
returns the list of selected filenames, while setting setDescritions to the state the checkbox was le...
void customEvent(QCustomEvent *e)
handle update events that come from the GeneratePreviewThread
QLabel * fileDetails
details about last selected file
QLabel * filePreview
preview of last selected file
QSize minimumSizeHint() const
GeneratePreviewThread * generatorThread
a worker thread that actually generates the file preview image and details information that is displa...
FilePreview(QWidget *parent=0)
void updatePreview(const QString &path)
call this function to update the file preview
GeneratePreviewThread(FilePreview *previewWidget)
void start(QString filename)
bool updating
is the worker thread currently generating a file preview?
QMutex lockingMutex
locking mutex - necessary to prevent multiple threads from accessing the updating bool or queue varia...
FilePreview * previewWidget
handle on preview widget necessary for posting an update event once the current file has been process...
QString filename
current file being processed
QString queue
next file to be processed by worker thread
UpdatePreviewEvent(QImage image, QString details)
QImage getImage() const
QString getDetails() const
bool scaleImage(QString fileIn, QString fileOut, int newWidth, int newHeight)
Scale image and save copy to disk.
bool getImageSize(const char *filename, QSize &size)
Get image dimensions.