1 /*************************************************************************** 2 kwave/FileContext.h - Context of a Loaded File 3 ------------------- 4 begin : 2009-12-31 5 copyright : (C) 2009 by Thomas.Eschenbacher 6 email : Thomas.Eschenbacher@gmx.de 7 ***************************************************************************/ 8 9 /*************************************************************************** 10 * * 11 * This program is free software; you can redistribute it and/or modify * 12 * it under the terms of the GNU General Public License as published by * 13 * the Free Software Foundation; either version 2 of the License, or * 14 * (at your option) any later version. * 15 * * 16 ***************************************************************************/ 17 18 #ifndef KWAVE_FILE_CONTEXT_H 19 #define KWAVE_FILE_CONTEXT_H 20 21 #include "config.h" 22 23 #include <QtGlobal> 24 #include <QAtomicInt> 25 #include <QElapsedTimer> 26 #include <QList> 27 #include <QObject> 28 #include <QPointer> 29 #include <QString> 30 #include <QTimer> 31 #include <QUrl> 32 33 #include "libkwave/MetaDataList.h" 34 #include "libkwave/Sample.h" 35 36 class QApplication; 37 class QMdiSubWindow; 38 class QSize; 39 class QTextStream; 40 class QWidget; 41 42 class QUrl; 43 44 namespace Kwave 45 { 46 47 class App; 48 class MainWidget; 49 class Parser; 50 class PluginManager; 51 class SignalManager; 52 class TopWidget; 53 class Zoomable; 54 55 class Q_DECL_EXPORT FileContext: public QObject 56 { 57 Q_OBJECT 58 public: 59 /** 60 * Constructor. Creates a new toplevel window, signal manager, 61 * plugin manager and so on. 62 * @param app reference to the Kwave application 63 */ 64 explicit FileContext(Kwave::App &app); 65 66 /** 67 * Destructor 68 */ 69 virtual ~FileContext(); 70 71 /** 72 * initializes the instance 73 * @param top_widget pointer to the toplevel widget 74 * @return true if successful 75 */ 76 bool init(Kwave::TopWidget *top_widget); 77 78 /** 79 * create a main widget, within the MDI area 80 * or toplevel widget in case of SDI interface 81 * @param preferred_size preferred size of the main widget 82 * @return true if successful, false if failed 83 */ 84 bool createMainWidget(const QSize &preferred_size); 85 86 /** 87 * migrate this context to a different toplevel widget 88 * @param top_widget pointer to the new toplevel widget 89 */ 90 void setParent(Kwave::TopWidget *top_widget); 91 92 /** returns a reference to the application instance */ app()93 Kwave::App &app() const { return m_application; } 94 95 /** 96 * returns a pointer to the main widget of this context 97 */ 98 QWidget *mainWidget() const; 99 100 /** returns a pointer to the signal manager of this context */ 101 Kwave::SignalManager *signalManager() const; 102 103 /** returns a pointer to the plugin manager of this context */ 104 Kwave::PluginManager *pluginManager() const; 105 106 /** 107 * Returns a pointer to a GUI element that receives zoom info 108 * (the MainWidget) 109 */ 110 Kwave::Zoomable *zoomable() const; 111 112 /** 113 * Returns whether this context is empty (has a main widget) or not. 114 * @retval true if the context is empty 115 * @retval false if the context has a main widget 116 */ isEmpty()117 inline bool isEmpty() const { return m_main_widget.isNull(); } 118 119 /** 120 * Returns whether this context is active or not. 121 * @retval true if the context is active 122 * @retval false if the context is inactive 123 */ isActive()124 inline bool isActive() const { return m_active; } 125 126 /** 127 * Returns true it this context has a signal (file is loaded) 128 * or the context is executing a script 129 */ 130 bool isInUse() const; 131 132 /** returns the name of the signal */ 133 QString signalName() const; 134 135 /** returns the instance of the loaded file or -1 */ instanceNr()136 inline int instanceNr() const { return m_instance_nr; } 137 138 /** 139 * returns a string suitable as window caption 140 * @param with_modified if true, include the "modified" state 141 */ 142 QString windowCaption(bool with_modified) const; 143 144 /** 145 * Loads a batch file into memory, parses and executes 146 * all commands in it. 147 * @param url URL of the macro (batch file) to be loaded 148 */ 149 int loadBatch(const QUrl &url); 150 151 /** 152 * Saves the current file. 153 * @return zero if succeeded, non-zero if failed 154 */ 155 int saveFile(); 156 157 /** 158 * Opens a dialog for saving the current file. 159 * @param filename the name of the new file 160 * or empty string to open the File/SaveAs dialog 161 * @param selection if set to true, only the current selection 162 * will be saved 163 * @return zero if succeeded, non-zero if failed 164 */ 165 int saveFileAs(const QString &filename, bool selection = false); 166 167 /** 168 * Closes the current file. 169 * If the file has been modified and the user wanted to cancel 170 * the close operation, the file will not get closed and the 171 * function returns with false. 172 * @return true if closing is allowed, false if canceled 173 */ 174 bool closeFile(); 175 176 protected: 177 friend class App; 178 friend class TopWidget; 179 friend class UsageGuard; 180 181 /** 182 * increments the usage count of this context, prevents it from 183 * being deleted 184 */ 185 void use(); 186 187 /** 188 * decrements the usage count of this context, and if it has reached 189 * zero this instance will be deleted (delayed) 190 */ 191 void release(); 192 193 signals: 194 195 /** 196 * emitted when there is a status bar message to show 197 * @param message the status bar message, already localized 198 * @param ms the time in milliseconds to show the message 199 */ 200 void sigStatusBarMessage(const QString &message, unsigned int ms); 201 202 /** 203 * emitted when the zoom factor of the corresponding main widget 204 * has changed 205 * @param context contains "this" 206 * @param zoom new zoom factor 207 */ 208 void sigZoomChanged(Kwave::FileContext *context, double zoom); 209 210 /** 211 * emitted when the meta data of the current signal has changed 212 * @param meta_data the new meta data, after the change 213 */ 214 void sigMetaDataChanged(Kwave::MetaDataList meta_data); 215 216 /** 217 * emits a change in the selected range. 218 * @param offset index of the first selected items 219 * @param length number of selected items 220 */ 221 void sigSelectionChanged(sample_index_t offset, sample_index_t length); 222 223 /** 224 * Emitted if the state or description of undo/redo has changed. If 225 * undo or redo is unavailable the description will be zero. 226 */ 227 void sigUndoRedoInfo(const QString &undo, const QString &redo); 228 229 /** emitted when the visible range has changed */ 230 void sigVisibleRangeChanged(sample_index_t offset, 231 sample_index_t visible, 232 sample_index_t total); 233 234 /** 235 * Emitted if the signal changes from non-modified to modified 236 * state or vice-versa. 237 */ 238 void sigModified(); 239 240 /** 241 * emitted when the context is about to be destroyed 242 * (in the context of it's destructor) 243 */ 244 void destroyed(Kwave::FileContext *context); 245 246 public slots: 247 248 /** 249 * Execute a Kwave text command 250 * @param command a text command 251 * @return zero if succeeded or negative error code if failed 252 */ 253 int executeCommand(const QString &command); 254 255 private slots: 256 257 /** 258 * called when the current file context has changed 259 * @param context the new file context (can be "this") 260 */ 261 void contextSwitched(Kwave::FileContext *context); 262 263 /** 264 * emits a sigZoomChanged(this, zoom) when the zoom has changed 265 * in the m_main_widget 266 */ 267 void forwardZoomChanged(double zoom); 268 269 /** 270 * Called when the playback position has changed 271 * @param offset the current playback position [samples] 272 */ 273 void updatePlaybackPos(sample_index_t offset); 274 275 /** 276 * Called when the meta data of the current signal has changed 277 * @param meta_data the new meta data, after the change 278 */ 279 void metaDataChanged(Kwave::MetaDataList meta_data); 280 281 /** 282 * Called when the number of selected samples has changed. 283 * @param offset index of the first selected sample 284 * @param length number of selected samples 285 */ 286 void selectionChanged(sample_index_t offset, sample_index_t length); 287 288 /** 289 * Called when the undo or redo action has changed. 290 * @param undo description of the last undo action 291 * @param redo description of the last redo action 292 */ 293 void setUndoRedoInfo(const QString &undo, const QString &redo); 294 295 /** 296 * Called after changes of the currently visible view range 297 * @param offset index of the first visible sample 298 * @param visible number of visible samples 299 * @param total length of the whole signal 300 */ 301 void visibleRangeChanged(sample_index_t offset, 302 sample_index_t visible, 303 sample_index_t total); 304 305 /** 306 * called if the signal now or no longer is modified 307 */ 308 void modifiedChanged(); 309 310 /** process the next delayed command from m_delayed_command_queue */ 311 void processDelayedCommand(); 312 313 private: 314 315 class UsageGuard 316 { 317 public: 318 /** 319 * constructor, increments use count 320 * @param context the file context to use 321 */ UsageGuard(Kwave::FileContext * context)322 explicit UsageGuard(Kwave::FileContext *context) 323 :m_context(context) 324 { 325 if (m_context) m_context->use(); 326 } 327 328 /** destructor, decrements use count of the context */ ~UsageGuard()329 virtual ~UsageGuard() 330 { 331 if (m_context) m_context->release(); 332 m_context = Q_NULLPTR; 333 } 334 335 private: 336 QPointer<Kwave::FileContext> m_context; 337 }; 338 339 private: 340 341 /** 342 * should be called when this context got active, to update 343 * the status bar, toolbar etc. 344 */ 345 void activated(); 346 347 /** 348 * Show a message in the status bar 349 * @param msg the status bar message, already localized 350 * @param ms the time in milliseconds to show the message 351 */ 352 void statusBarMessage(const QString &msg, unsigned int ms); 353 354 /** 355 * Parses a text stream line by line and executes each line 356 * as a command until all commands are done or the first one fails. 357 * @param stream a QTextStream to read from 358 * @return zero if successful, non-zero error code if a command failed 359 */ 360 int parseCommands(QTextStream &stream); 361 362 /** 363 * enqueues a command for later execution 364 * @param delay milliseconds to wait before execution 365 * @param command the command to execute 366 */ 367 void enqueueCommand(unsigned int delay, const QString &command); 368 369 /** 370 * Discards all changes to the current file and loads 371 * it again. 372 * @return zero if succeeded or error code 373 */ 374 int revert(); 375 376 /** 377 * delegate a command to a plugin 378 * @param plugin name of a plugin to delegate the command to 379 * @param parser the parser with the parts of the command 380 * @param param_count required number of parameters 381 */ 382 int delegateCommand(const char *plugin, 383 Kwave::Parser &parser, 384 unsigned int param_count); 385 386 private: 387 388 /** usage counter [0...n] */ 389 QAtomicInt m_use_count; 390 391 /** reference to the global Kwave application object */ 392 Kwave::App &m_application; 393 394 /** instance of our toplevel window */ 395 QPointer<Kwave::TopWidget> m_top_widget; 396 397 /** instance of our main widget */ 398 QPointer<Kwave::MainWidget> m_main_widget; 399 400 /** instance of our signal manager */ 401 QPointer<Kwave::SignalManager> m_signal_manager; 402 403 /** instance of our plugin manager */ 404 QPointer<Kwave::PluginManager> m_plugin_manager; 405 406 /** if true, this context is active, otherwise it is inactive */ 407 bool m_active; 408 409 /** last zoom factor */ 410 double m_last_zoom; 411 412 /** last playback position, only valid if playback is running */ 413 sample_index_t m_last_playback_pos; 414 415 /** last status bar message */ 416 QString m_last_status_message_text; 417 418 /** time when the last status message has been shown */ 419 QElapsedTimer m_last_status_message_timer; 420 421 /** number of milliseconds the status message should be shown */ 422 unsigned int m_last_status_message_ms; 423 424 /** name of the last undo action */ 425 QString m_last_undo; 426 427 /** name of the last redo action */ 428 QString m_last_redo; 429 430 /** instance of the loaded file or -1 */ 431 int m_instance_nr; 432 433 /** timer for delayed commands */ 434 QTimer m_delayed_command_timer; 435 436 /** queue for delayed execution of commands */ 437 QList< QPair<unsigned int, QString> > m_delayed_command_queue; 438 439 }; 440 441 } 442 443 #endif /* KWAVE_FILE_CONTEXT_H */ 444 445 //*************************************************************************** 446 //*************************************************************************** 447