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 //==============================================
GeneratePreviewThread * generatorThread
a worker thread that actually generates the file preview image and details information that is displa...
void updatePreview(const QString &filename)
handle the user selecting items by updating the file preview fields
UpdatePreviewEvent(QImage image, QString details)
FilePreview * filePreview
Used to preview selected files.
#define MIN_HEIGHT
QLabel * fileDetails
details about last selected file
GeneratePreviewThread(FilePreview *previewWidget)
FilePreview(QWidget *parent=0)
void customEvent(QCustomEvent *e)
handle update events that come from the GeneratePreviewThread
QStringList getFilenames(bool &setDescriptions)
returns the list of selected filenames, while setting setDescritions to the state the checkbox was le...
QLabel * filePreview
preview of last selected file
#define UPDATE_PREVIEW_DETAILS
void updatePreview(const QString &path)
call this function to update the file preview
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
QImage getImage() const
void start(QString filename)
#define MIN_WIDTH
QSize minimumSizeHint() const
AddPhotosDialog(QString path, QWidget *parent=0, const char *name=0)
QCheckBox * setDescriptions
Checkbox asking if filenames should be used to set image descriptions.