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
205 int progress
/// The progress of the encoding - "the number of pixels encoded"
206 , maxProgress
; ///< The maximum value of progress
208 IRoot
*modules_encoding
;///< The encoding modules
209 UpdateInfo updateInfo
; ///< UpdateInfo passed to encoding modules
211 QTimer updateTimer
; ///< Updates the dialog regularly
212 QTime encTime
; ///< Measures encoding time
213 EncThread encThread
; ///< The encoding thread
216 /** Sets the maximum progress (the value corresponding to 100%) */
217 static void incMaxProgress(int increment
) {
218 instance
->maxProgress
+= increment
;
219 instance
->needUpdate
= true;
221 /** Increase the progress by a value */
222 static void incProgress(int increment
) {
223 instance
->progress
+= increment
;
224 instance
->needUpdate
= true;
226 // TODO: Should we provide a thread-safe version?
227 // q_atomic_fetch_and_add_acquire_int(&instance->progress,increment);
228 // instance->setValue((volatile int&)instance->progress);
231 /** Slot for catching cancel-pressed signal */
234 /** Updating slot - called regularly by a timer */
239 setMaximum(maxProgress
);
243 /** Creates and initializes the dialog */
244 EncodingProgress(ImageViewer
*parent
)
245 : QProgressDialog( tr("Encoding..."), tr("Cancel"), 0, 100, parent
, Qt::Dialog
)
246 , terminate(false), needUpdate(false)
247 , progress(0), maxProgress(0)
248 , modules_encoding(clone(parent
->modules_settings
))
249 , updateInfo( terminate
, &incMaxProgress
, &incProgress
), updateTimer(this)
250 , encThread( modules_encoding
, parent
->imageLabel
->pixmap()->toImage(), updateInfo
) {
253 // set some dialog features
254 setWindowModality(Qt::ApplicationModal
);
257 // to switch to terminating status when cancel is clicked
258 aConnect( this, SIGNAL(canceled()), this, SLOT(setTerminate()) );
259 // start the updating timer
260 aConnect( &updateTimer
, SIGNAL(timeout()), this, SLOT(update()) );
261 updateTimer
.start(500);
262 encTime
.start(); // start measuring the time
263 // start the encoding thread, set it to call ImageViewer::encDone when finished
264 aConnect( &encThread
, SIGNAL(finished()), parent
, SLOT(encDone()) );
265 encThread
.start(QThread::LowPriority
);
267 /** Only zeroes #instance */
268 ~EncodingProgress() {
269 ASSERT(this==instance
);
273 /** Creates the dialog and starts encoding */
274 static void create(ImageViewer
*parent
) {
275 new EncodingProgress(parent
);
277 /** Collects results and destroys the dialog */
278 static IRoot
* destroy(int &elapsed
) {
279 ASSERT( instance
&& instance
->encThread
.isFinished() );
280 // get the encoding result if successful, delete it otherwise
281 IRoot
*result
= instance
->modules_encoding
;
282 if ( !instance
->encThread
.getSuccess() ) {
286 elapsed
= instance
->encTime
.elapsed();
291 }; // EncodingProgress class
293 #endif // GUI_HEADER_