7 #include <QApplication>
9 #include <QDialogButtonBox>
10 #include <QDoubleSpinBox>
11 #include <QFileDialog>
13 #include <QGridLayout>
16 #include <QMainWindow>
19 #include <QMessageBox>
20 #include <QMouseEvent>
21 #include <QProgressDialog>
22 #include <QScrollArea>
29 #include <QTranslator>
30 #include <QTreeWidgetItem>
34 class EncodingProgress
;
36 /** Represents the main window of the program, providing a GUI */
37 class ImageViewer
: public QMainWindow
{ Q_OBJECT
38 friend class SettingsDialog
;
39 friend class EncodingProgress
;
41 static const int AutoIterationCount
= 10;
43 IRoot
*modules_settings
/// Module tree holding current settings
44 , *modules_encoding
; ///< Module tree that's currently encoding or the last one
45 int zoom
; ///< The current zoom, see IRoot::fromStream
46 std::string encData
; ///< String containing (if nonempty) the last encoded/decoded data
48 QTranslator
&translator
;///< The application's only translator
49 QLabel
*imageLabel
; ///< A pointer to the label showing images
55 readAct
, writeAct
, compareAct
, exitAct
,
56 settingsAct
, encodeAct
, saveAct
,
57 loadAct
, clearAct
, iterateAct
, zoomIncAct
, zoomDecAct
,
58 loadLangAct
, useLangAct
;
59 //aboutAct, aboutQtAct;
63 QMenu imageMenu
, compMenu
, decompMenu
, langMenu
;//, helpMenu;
65 void createActions(); ///< Creates all actions and connects them to correct slots
66 void createMenus(); ///< Creates the menu bar and fills it with actions
67 void translateUi(); ///< Sets all texts in the application (uses current language)
68 void updateActions(); ///< Updates the availability of all actions
69 void changePixmap(const QPixmap
&pixmap
) {
70 imageLabel
->setPixmap(pixmap
);
71 imageLabel
->resize( pixmap
.size() );
72 } ///< Shows a new image
74 /** \name Methods performing the actions
88 void useLang(bool use
);
94 /** Initializes the object to default settings */
95 ImageViewer(QApplication
&app
,QTranslator
&trans
);
96 /** Only releases the modules */
97 virtual ~ImageViewer()
98 { delete modules_settings
; delete modules_encoding
; }
100 /** Reloads the image, iterates and shows it (returns true on success) */
102 /** Gets the path of the last used directory (from ::lastPath) */
104 { QDir
dir(lastPath
); return dir
.cdUp() ? dir
.path() : QDir::currentPath(); }
106 void mousePressEvent(QMouseEvent
*event
);
110 /** A simple wrapper around QObject::connect that asserts successfulness of the connection */
111 inline void aConnect( const QObject
*sender
, const char *signal
, const QObject
*receiver
112 , const char *slot
, Qt::ConnectionType type
=Qt::AutoCompatConnection
) {
113 DEBUG_ONLY( bool result
= )
114 QObject::connect(sender
,signal
,receiver
,slot
,type
);
118 /** Represents the encoding-settings dialog */
119 class SettingsDialog
: public QDialog
{ Q_OBJECT
120 QGroupBox
*setBox
; ///< the settings group-box
121 QTreeWidget
*treeWidget
; ///< the settings tree
122 QDialogButtonBox
*loadSaveButtons
; ///< the button-box for loading and saving
123 IRoot
*settings
; ///< the settings we edit
125 /** Returns a reference to the parent instance of ImageViewer */
126 ImageViewer
& parentViewer() {
127 ImageViewer
*result
= debugCast
<ImageViewer
*>(parent());
131 /** Initializes the settings tree and group-box contents from ::settings */
134 /** Changes the contents of the settings group-box when selecting in the settings tree */
135 void currentItemChanged(QTreeWidgetItem
*current
,QTreeWidgetItem
*previous
);
136 /** Adjusts the ::settings when changed in the settings group-box */
137 void settingChanges(int which
);
138 /** Handles loading and saving of the settings */
139 void loadSaveClick(QAbstractButton
*button
);
141 /** Initializes all the widgets in the dialog */
142 SettingsDialog(ImageViewer
*parent
,IRoot
*settingsHolder
);
143 /** Returns the edited ::settings */
144 IRoot
* getSettings() { return settings
; }
147 /** Converts signals from various types of widgets */
148 class SignalChanger
: public QObject
{ Q_OBJECT
151 /** Configures to emit notify(\p whichSignal) when the state of widget \p parent changes
152 * (it represents settings of type \p type) */
153 SignalChanger( int whichSignal
, QWidget
*parent
=0, Module::ChoiceType type
=Module::Stop
)
154 : QObject(parent
), signal(whichSignal
) {
157 // connect widget's changing signal to my notifyXxx slot
158 const char *signalString
=0, *slotString
=0;
161 case Module::IntLog2
:
162 signalString
= SIGNAL(valueChanged(int));
163 slotString
= SLOT(notifyInt(int));
166 signalString
= SIGNAL(valueChanged(double));
167 slotString
= SLOT(notifyDouble(double));
169 case Module::ModuleCombo
:
171 signalString
= SIGNAL(currentIndexChanged(int));
172 slotString
= SLOT(notifyInt(int));
177 aConnect( parent
, signalString
, this, slotString
);
180 void notifyInt(int) { emit
notify(signal
); }
181 void notifyDouble(double) { emit
notify(signal
); }
184 }; // SignalChanger class
188 /** A dialog showing encoding progress */
189 class EncodingProgress
: public QProgressDialog
{ Q_OBJECT
190 /** Encoding-thread type */
191 class EncThread
: public QThread
{ //Q_OBJECT
195 UpdateInfo updateInfo
;
197 EncThread(IRoot
*root_
,const QImage
&image_
,const UpdateInfo
&updateInfo_
)
198 : root(root_
), image(image_
), updateInfo(updateInfo_
) {}
200 { success
= root
->encode(image
,updateInfo
); }
201 bool getSuccess() const
203 }; // EncThread class
205 static EncodingProgress
*instance
; ///< Pointer to the single instance of the class
207 bool terminate
/// Value indicating whether the encoding should be interrupted
210 int progress
/// The progress of the encoding - "the number of pixels encoded"
211 , maxProgress
; ///< The maximum value of progress
213 IRoot
*modules_encoding
;///< The encoding modules
214 UpdateInfo updateInfo
; ///< UpdateInfo passed to encoding modules
216 QTimer updateTimer
; ///< Updates the dialog regularly
217 QTime encTime
; ///< Measures encoding time
218 EncThread encThread
; ///< The encoding thread
221 /** Sets the maximum progress (the value corresponding to 100%) */
222 static void incMaxProgress(int increment
) {
223 instance
->maxProgress
+= increment
;
224 instance
->updateMaxProgress
= true;
226 /** Increase the progress by a value */
227 static void incProgress(int increment
) {
228 instance
->progress
+= increment
;
229 //< a race can occur, but only affects progress display
230 instance
->updateProgress
= true;
234 /** Slot for catching cancel-pressed signal */
237 /** Updating slot - called regularly by a timer */
239 if (updateMaxProgress
) {
240 setMaximum(maxProgress
);
241 updateMaxProgress
= false;
243 if (updateProgress
) {
245 updateProgress
= false;
249 /** Creates and initializes the dialog */
250 EncodingProgress(ImageViewer
*parent
)
251 : QProgressDialog( tr("Encoding..."), tr("Cancel"), 0, 100, parent
, Qt::Dialog
)
252 , terminate(false), updateMaxProgress(false), updateProgress(false)
253 , progress(0), maxProgress(0)
254 , modules_encoding(parent
->modules_settings
->clone())
255 , updateInfo( terminate
, &incMaxProgress
, &incProgress
), updateTimer(this)
256 , encThread( modules_encoding
, parent
->imageLabel
->pixmap()->toImage(), updateInfo
) {
259 // set some dialog features
260 setWindowModality(Qt::ApplicationModal
);
263 // to switch to terminating status when cancel is clicked
264 aConnect( this, SIGNAL(canceled()), this, SLOT(setTerminate()) );
265 // start the updating timer
266 aConnect( &updateTimer
, SIGNAL(timeout()), this, SLOT(update()) );
267 updateTimer
.start(1000);
268 encTime
.start(); // start measuring the time
269 // start the encoding thread, set it to call ImageViewer::encDone when finished
270 aConnect( &encThread
, SIGNAL(finished()), parent
, SLOT(encDone()) );
271 encThread
.start(QThread::LowPriority
);
273 /** Only zeroes #instance */
274 ~EncodingProgress() {
275 ASSERT(this==instance
);
279 /** Creates the dialog and starts encoding */
280 static void create(ImageViewer
*parent
) {
281 new EncodingProgress(parent
);
283 /** Collects results and destroys the dialog */
284 static IRoot
* destroy(int &elapsed
) {
285 ASSERT( instance
&& instance
->encThread
.isFinished() );
286 // get the encoding result if successful, delete it otherwise
287 IRoot
*result
= instance
->modules_encoding
;
288 if ( !instance
->encThread
.getSuccess() ) {
292 elapsed
= instance
->encTime
.elapsed();
297 }; // EncodingProgress class
299 #endif // GUI_HEADER_