Fixed wrong prediction for incomplete ranges.
[fic.git] / gui.h
blobfdac49c22077ff38e7228aec359696b5d9612ad5
1 #ifndef GUI_HEADER_
2 #define GUI_HEADER_
4 #include "headers.h"
6 #include <QAction>
7 #include <QApplication>
8 #include <QComboBox>
9 #include <QDialogButtonBox>
10 #include <QDoubleSpinBox>
11 #include <QFileDialog>
12 #include <QFileInfo>
13 #include <QGridLayout>
14 #include <QGroupBox>
15 #include <QLabel>
16 #include <QMainWindow>
17 #include <QMenu>
18 #include <QMenuBar>
19 #include <QMessageBox>
20 #include <QMouseEvent>
21 #include <QProgressDialog>
22 #include <QScrollArea>
23 #include <QScrollBar>
24 #include <QSpinBox>
25 #include <QStatusBar>
26 #include <QThread>
27 #include <QTime>
28 #include <QTimer>
29 #include <QTranslator>
30 #include <QTreeWidgetItem>
32 class ImageViewer;
33 class SettingsDialog;
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
51 QDir lastPath;
52 /** \name Actions
53 * @{ */
54 QAction
55 readAct, writeAct, compareAct, exitAct,
56 settingsAct, encodeAct, saveAct,
57 loadAct, clearAct, iterateAct, zoomIncAct, zoomDecAct,
58 loadLangAct, useLangAct;
59 //aboutAct, aboutQtAct;
60 /// @}
61 /** \name Menus
62 * @{ */
63 QMenu imageMenu, compMenu, decompMenu, langMenu;//, helpMenu;
64 /// @}
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
73 private slots:
74 /** \name Methods performing the actions
75 @{ */
76 void read();
77 void write();
78 void compare();
79 void settings();
80 void encode();
81 void save();
82 void load();
83 void clear();
84 void iterate();
85 void zoomInc();
86 void zoomDec();
87 void loadLang();
88 void useLang(bool use);
89 //void about();
90 //void aboutQt();
91 /// @}
92 void encDone();
93 public:
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; }
99 private:
100 /** Reloads the image, iterates and shows it (returns true on success) */
101 bool rezoom();
102 /** Gets the path of the last used directory (from ::lastPath) */
103 QString lastDir()
104 { QDir dir(lastPath); return dir.cdUp() ? dir.path() : QDir::currentPath(); }
105 #ifndef NDEBUG
106 void mousePressEvent(QMouseEvent *event);
107 #endif
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);
115 ASSERT(result);
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());
128 ASSERT(result);
129 return *result;
131 /** Initializes the settings tree and group-box contents from ::settings */
132 void initialize();
133 private slots:
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);
140 public:
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
149 int signal;
150 public:
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) {
155 if (!parent)
156 return;
157 // connect widget's changing signal to my notifyXxx slot
158 const char *signalString=0, *slotString=0;
159 switch (type) {
160 case Module::Int:
161 case Module::IntLog2:
162 signalString= SIGNAL(valueChanged(int));
163 slotString= SLOT(notifyInt(int));
164 break;
165 case Module::Float:
166 signalString= SIGNAL(valueChanged(double));
167 slotString= SLOT(notifyDouble(double));
168 break;
169 case Module::ModuleCombo:
170 case Module::Combo:
171 signalString= SIGNAL(currentIndexChanged(int));
172 slotString= SLOT(notifyInt(int));
173 break;
174 default:
175 ASSERT(false);
176 }// switch
177 aConnect( parent, signalString, this, slotString );
179 public slots:
180 void notifyInt(int) { emit notify(signal); }
181 void notifyDouble(double) { emit notify(signal); }
182 signals:
183 void notify(int);
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
192 IRoot *root;
193 QImage image;
194 bool success;
195 UpdateInfo updateInfo;
196 public:
197 EncThread(IRoot *root_,const QImage &image_,const UpdateInfo &updateInfo_)
198 : root(root_), image(image_), updateInfo(updateInfo_) {}
199 virtual void run()
200 { success= root->encode(image,updateInfo); }
201 bool getSuccess() const
202 { return success; }
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
208 , updateMaxProgress
209 , updateProgress;
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
220 private:
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;
233 private slots:
234 /** Slot for catching cancel-pressed signal */
235 void setTerminate()
236 { terminate= true; }
237 /** Updating slot - called regularly by a timer */
238 void update() {
239 if (updateMaxProgress) {
240 setMaximum(maxProgress);
241 updateMaxProgress= false;
243 if (updateProgress) {
244 setValue(progress);
245 updateProgress= false;
248 private:
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 ) {
257 ASSERT(!instance);
258 instance= this;
259 // set some dialog features
260 setWindowModality(Qt::ApplicationModal);
261 setAutoClose(false);
262 setAutoReset(false);
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);
276 instance= 0;
278 public:
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() ) {
289 delete result;
290 result= 0;
292 elapsed= instance->encTime.elapsed();
293 // delete the dialog
294 delete instance;
295 return result;
297 }; // EncodingProgress class
299 #endif // GUI_HEADER_