4 #include "interfaces.h"
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
;
61 QMenu imageMenu
, compMenu
, decompMenu
;//, langMenu, helpMenu;
63 void createActions(); ///< Creates all actions and connects them to correct slots
64 void createMenus(); ///< Creates the menu bar and fills it with actions
65 void translateUi(); ///< Sets all texts in the application (uses current language)
66 void updateActions(); ///< Updates the availability of all actions
67 void changePixmap(const QPixmap
&pixmap
) {
68 imageLabel
->setPixmap(pixmap
);
69 imageLabel
->resize( pixmap
.size() );
70 } ///< Shows a new image
72 /** \name Methods performing the actions
88 /** Initializes the object to default settings */
89 ImageViewer(QApplication
&app
);
90 /** Only releases the modules */
91 virtual ~ImageViewer()
92 { delete modules_settings
; delete modules_encoding
; }
94 /** Reloads the image, iterates and shows it (returns true on success) */
96 /** Gets the path of the last used directory (from ::lastPath) */
98 { QDir
dir(lastPath
); return dir
.cdUp() ? dir
.path() : QDir::currentPath(); }
100 void mousePressEvent(QMouseEvent
*event
);
104 /** A simple wrapper around QObject::connect that asserts successfulness of the connection */
105 inline void aConnect( const QObject
*sender
, const char *signal
, const QObject
*receiver
106 , const char *slot
, Qt::ConnectionType type
=Qt::AutoCompatConnection
) {
110 QObject::connect(sender
,signal
,receiver
,slot
,type
);
114 /** Represents the encoding-settings dialog */
115 class SettingsDialog
: public QDialog
{ Q_OBJECT
116 QGroupBox
*setBox
; ///< the settings group-box
117 QTreeWidget
*treeWidget
; ///< the settings tree
118 QDialogButtonBox
*loadSaveButtons
; ///< the button-box for loading and saving
119 IRoot
*settings
; ///< the settings we edit
121 /** Returns a reference to the parent instance of ImageViewer */
122 ImageViewer
& parentViewer() {
123 ImageViewer
*result
= debugCast
<ImageViewer
*>(parent());
127 /** Initializes the settings tree and group-box contents from #settings */
130 /** Changes the contents of the settings group-box when selecting in the settings tree */
131 void currentItemChanged(QTreeWidgetItem
*current
,QTreeWidgetItem
*previous
);
132 /** Adjusts the #settings when changed in the settings group-box */
133 void settingChanges(int which
);
134 /** Handles loading and saving of the settings */
135 void loadSaveClick(QAbstractButton
*button
);
137 /** Initializes all the widgets in the dialog */
138 SettingsDialog(ImageViewer
*parent
,IRoot
*settingsHolder
);
139 /** Returns the edited #settings */
140 IRoot
* getSettings() { return settings
; }
143 /** Converts signals from various types of widgets */
144 class SignalChanger
: public QObject
{ Q_OBJECT
147 /** Configures to emit notify(\p whichSignal) when the state of widget \p parent changes
148 * (it represents settings of type \p type) */
149 SignalChanger( int whichSignal
, QWidget
*parent
=0, Module::ChoiceType type
=Module::Stop
)
150 : QObject(parent
), signal(whichSignal
) {
153 // connect widget's changing signal to my notifyXxx slot
154 const char *signalString
=0, *slotString
=0;
157 case Module::IntLog2
:
158 signalString
= SIGNAL(valueChanged(int));
159 slotString
= SLOT(notifyInt(int));
162 signalString
= SIGNAL(valueChanged(double));
163 slotString
= SLOT(notifyDouble(double));
165 case Module::ModuleCombo
:
167 signalString
= SIGNAL(currentIndexChanged(int));
168 slotString
= SLOT(notifyInt(int));
173 aConnect( parent
, signalString
, this, slotString
);
176 void notifyInt(int) { emit
notify(signal
); }
177 void notifyDouble(double) { emit
notify(signal
); }
180 }; // SignalChanger class
184 /** A dialog showing encoding progress */
185 class EncodingProgress
: public QProgressDialog
{ Q_OBJECT
186 /** Encoding-thread type */
187 class EncThread
: public QThread
{ //Q_OBJECT
191 UpdateInfo updateInfo
;
193 EncThread(IRoot
*root_
,const QImage
&image_
,const UpdateInfo
&updateInfo_
)
194 : root(root_
), image(image_
), updateInfo(updateInfo_
) {}
196 { success
= root
->encode(image
,updateInfo
); }
197 bool getSuccess() const
199 }; // EncThread class
201 static EncodingProgress
*instance
; ///< Pointer to the single instance of the class
203 bool terminate
/// Value indicating whether the encoding should be interrupted
206 int progress
/// The progress of the encoding - "the number of pixels encoded"
207 , maxProgress
; ///< The maximum value of progress
209 IRoot
*modules_encoding
;///< The encoding modules
210 UpdateInfo updateInfo
; ///< UpdateInfo passed to encoding modules
212 QTimer updateTimer
; ///< Updates the dialog regularly
213 QTime encTime
; ///< Measures encoding time
214 EncThread encThread
; ///< The encoding thread
217 /** Sets the maximum progress (the value corresponding to 100%) */
218 static void incMaxProgress(int increment
) {
219 instance
->maxProgress
+= increment
;
220 instance
->updateMaxProgress
= true;
222 /** Increase the progress by a value */
223 static void incProgress(int increment
) {
224 instance
->progress
+= increment
;
225 instance
->updateProgress
= true;
227 /// \todo Should we provide a thread-safe version?
228 /// q_atomic_fetch_and_add_acquire_int(&instance->progress,increment);
229 /// instance->setValue((volatile int&)instance->progress);
232 /** Slot for catching cancel-pressed signal */
235 /** Updating slot - called regularly by a timer */
237 if (updateMaxProgress
) {
238 setMaximum(maxProgress
);
239 updateMaxProgress
= false;
241 if (updateProgress
) {
243 updateProgress
= false;
247 /** Creates and initializes the dialog */
248 EncodingProgress(ImageViewer
*parent
)
249 : QProgressDialog( tr("Encoding..."), tr("Cancel"), 0, 100, parent
, Qt::Dialog
)
250 , terminate(false), updateMaxProgress(false), updateProgress(false)
251 , progress(0), maxProgress(0)
252 , modules_encoding(parent
->modules_settings
->clone())
253 , updateInfo( terminate
, &incMaxProgress
, &incProgress
), updateTimer(this)
254 , encThread( modules_encoding
, parent
->imageLabel
->pixmap()->toImage(), updateInfo
) {
257 // set some dialog features
258 setWindowModality(Qt::ApplicationModal
);
261 // to switch to terminating status when cancel is clicked
262 aConnect( this, SIGNAL(canceled()), this, SLOT(setTerminate()) );
263 // start the updating timer
264 aConnect( &updateTimer
, SIGNAL(timeout()), this, SLOT(update()) );
265 updateTimer
.start(1000);
266 encTime
.start(); // start measuring the time
267 // start the encoding thread, set it to call ImageViewer::encDone when finished
268 aConnect( &encThread
, SIGNAL(finished()), parent
, SLOT(encDone()) );
269 encThread
.start(QThread::LowPriority
);
271 /** Only zeroes #instance */
272 ~EncodingProgress() {
273 ASSERT(this==instance
);
277 /** Creates the dialog and starts encoding */
278 static void create(ImageViewer
*parent
) {
279 new EncodingProgress(parent
);
281 /** Collects results and destroys the dialog */
282 static IRoot
* destroy(int &elapsed
) {
283 ASSERT( instance
&& instance
->encThread
.isFinished() );
284 // get the encoding result if successful, delete it otherwise
285 IRoot
*result
= instance
->modules_encoding
;
286 if ( !instance
->encThread
.getSuccess() ) {
290 elapsed
= instance
->encTime
.elapsed();
295 }; // EncodingProgress class
297 #endif // GUI_HEADER_