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"
31 #include "../../backend/tools/imageTools.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 {
45 public:
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 
58 private:
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 //================================
75 void 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  {
83  queue = filename;
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 //==============================================
229 void 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 //==============================================
241 AddPhotosDialog::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 //==============================================
268 QStringList 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 //==============================================
278 void 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.
Definition: imageTools.cpp:157
bool getImageSize(const char *filename, QSize &size)
Get image dimensions.
Definition: imageTools.cpp:192