1 /*! 2 * @file mainwindow.h 3 * @brief Member definitions for the MainWindow top-level UI class. 4 * 5 * 6 * Copyright 2009 - 2017 <qmidiarp-devel@lists.sourceforge.net> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 21 * MA 02110-1301, USA. 22 * 23 */ 24 25 #ifndef MAINWINDOW_H 26 #define MAINWINDOW_H 27 28 #include <QApplication> 29 #include <QCloseEvent> 30 #include <QMessageBox> 31 #include <QMainWindow> 32 #include <QToolBar> 33 34 #include "logwidget.h" 35 #include "midicctable.h" 36 #include "passwidget.h" 37 #include "globstore.h" 38 39 #ifdef NSM 40 #include "nsm.h" 41 #endif 42 43 44 static const char ABOUTMSG[] = 45 "<html> <p><b><big>" APP_NAME " " PACKAGE_VERSION "</big></b></p>" 46 "<p>(C) 2009 - 2017 Frank Kober<br/>" 47 "(C) 2011 Nedko Arnaudov<br/>" 48 "(C) 2009 Guido Scholz<br/>" 49 "(C) 2002-2003 Matthias Nagorni (SuSE AG Nuremberg)<br/></p>" 50 "<p><b>Contributions</b><br/>" 51 "Roy Vegard Ovesen (work on nsm support)<br/></p>" 52 "<p><b>Translations</b><br/>" 53 "Pavel Fric<br/>" 54 "Pedro Lopez-Cabanillas<br/>" 55 "Robert Dietrich<br/></p>" 56 "<p>For getting support please type <b>man qmidiarp</b> or go to<br/>" 57 "<a href=\"http://qmidiarp.sourceforge.net\">" 58 "http://qmidiarp.sourceforge.net</a></p>" 59 APP_NAME " is licensed under the GPLv2.</b></p></html>"; 60 61 /*! 62 * The MainWindow class is the main UI that holds functions to manage global 63 * QMidiArp parameters and modules and to load and save parameters to 64 * disk. The constructor sets up all main window elements including 65 * toolbars and menus. It instantiates the LogWidget, PassWidget, 66 * MidiCCTable and their DockWidget windows. It also instantiates the 67 * Engine widget holding the lists of modules. 68 69 * @brief Top-level UI class. Instantiates Engine 70 */ 71 class MainWindow : public QMainWindow 72 { 73 Q_OBJECT 74 75 private: 76 static int sigpipe[2]; 77 bool alsaMidi; 78 QSpinBox *tempoSpin; 79 PassWidget *passWidget; 80 GrooveWidget *grooveWidget; 81 LogWidget *logWidget; 82 GlobStore *globStore; 83 Engine *engine; 84 MidiCCTable *midiCCTable; 85 QString lastDir, filename; 86 QStringList patternNames, patternPresets; 87 QStringList recentFiles; 88 QDockWidget *logWindow, *grooveWindow, *passWindow, *globStoreWindow; 89 90 QToolBar *controlToolBar, *fileToolBar; 91 QAction *runAction, *addArpAction; 92 QAction *addLfoAction, *addSeqAction; 93 QAction *fileNewAction, *fileOpenAction, *fileSaveAction, *fileSaveAsAction; 94 QAction *fileQuitAction; 95 QAction *midiClockAction, *jackSyncAction; 96 QAction *showAllIOAction, *hideAllIOAction; 97 QMenu* fileRecentlyOpenedFiles; 98 99 #ifdef NSM 100 static nsm_client_t *nsm; 101 QString configFile; 102 #endif 103 /*! 104 * @brief opens a file dialog and calls MainWindow::openFile(). 105 * It is called by MainWindow::fileOpen(). 106 */ 107 void chooseFile(); 108 /*! @brief checks whether parameter modifications 109 * were done after the last save. 110 * 111 * If yes, it queries the user how to handle unsaved changes using a 112 * message box. 113 * @return True if the parameters can be overwritten 114 */ 115 bool isSave(); 116 void updateWindowTitle(); 117 /*! 118 * @brief opens a QMidiArp XML session file named 119 * MainWindow::filename for write using QXmlStreamReader. 120 * 121 * It writes global and GUI parameters and and calls the 122 * block writers in the module widgets. 123 * 124 * @return True if write was successful 125 */ 126 bool saveFile(); 127 /*! @brief opens a file dialog and appends the file extension to 128 * the chosen name if not present. It is called by fileSaveAs. 129 * @return True if a file name was successfully chosen 130 */ 131 bool saveFileAs(); 132 /*! 133 * @brief returns the result of Engine::isModified 134 * @return True if unsaved parameter modifications exist in any module 135 * 136 */ 137 bool isModified(); 138 /*! 139 * @brief creates and adds a new MidiArp to Engine. 140 * 141 * It also creates and adds the associated ArpWidget 142 * and DockWidget to the corresponding lists in Engine. It sets 143 * the ManageBox::name and ManageBox::ID as the current count of the 144 * Engine::midiArpList. 145 * 146 * @param name Name attribute of the created arpeggiator module 147 * @param fromfile Set to True if module is added by a file read 148 * @param inOutVisible Set to True if In-Out panel should be shown 149 */ 150 void addArp(const QString& name, bool fromfile = false, 151 bool inOutVisible = true); 152 /*! 153 * @brief creates and adds a new MidiLfo to Engine. 154 * 155 * It also creates and adds the associated LfoWidget 156 * and DockWidget to the corresponding lists in Engine. It sets 157 * the ManageBox::name and ManageBox::ID as the current count of the 158 * Engine::midiLfoList. 159 * 160 * @param name Name attribute of this LFO module 161 * @param fromfile Set to True if module is added by a file read 162 * @param clonefrom Set to the ID to clone this module from, 163 * -1 for a new module (default) 164 * @param inOutVisible Set to True if In-Out panel should be shown 165 */ 166 void addLfo(const QString& name, bool fromfile = false, 167 int clonefrom = -1, bool inOutVisible = true); 168 /*! 169 * @brief creates and adds a new MidiSeq to Engine. 170 * 171 * It also creates and adds the associated SeqWidget 172 * and DockWidget to the corresponding lists in Engine. It sets 173 * the ManageBox::name and ManageBox::ID as the current count of the 174 * Engine::midiSeqList. 175 * 176 * @param name Name attribute of this module 177 * @param fromfile Set to True if module is added by a file read 178 * @param clonefrom Set to the ID to clone this module from, 179 * -1 for a new module (default) 180 * @param inOutVisible Set to True if In-Out panel should be shown 181 */ 182 void addSeq(const QString& name, bool fromfile = false, 183 int clonefrom = -1, bool inOutVisible = true); 184 /*! 185 * @brief wraps the given widget in a QDockWidget and adds 186 * it to the list in Engine. 187 * 188 * @param *moduleWidget The QWidget to be embedded 189 * @param name Name attribute of this module 190 * @param count DockWidget list location at which the window is insertet 191 */ 192 void appendDock(QWidget *moduleWidget, const QString& name, int count); 193 /*! 194 * @brief reads global parameter block from an XML session 195 * stream using the QXmlStreamReader passed by the caller. 196 * 197 * @param xml Reference to QXmlStreamReader containing the open XML stream 198 */ 199 void readFilePartGlobal(QXmlStreamReader& xml); 200 /*! 201 * @brief reads the module parameter blocks from the XML stream 202 * by calling their read functions. 203 * 204 * It uses the first three letters of the module name to distinguish their 205 * type. It creates the according module components and calls their UI 206 * widgets, which fill them with the parameters found in the same stream. 207 * Calls Engine->NNNWidget->readData, where NNN is Arp, Lfo or Seq. 208 * 209 * @param xml Reference to QXmlStreamReader containing the open XML stream 210 */ 211 void readFilePartModules(QXmlStreamReader& xml); 212 /*! 213 * @brief reads the GUI settings block 214 * from the XML session stream passed by the caller. 215 * 216 * @param xml Reference to QXmlStreamReader containing the XML stream 217 */ 218 void readFilePartGUI(QXmlStreamReader& xml); 219 /*! 220 * @brief prepends a filename at the beginning of the recently 221 * opened files list. 222 * 223 * It is called by openFile if the opening was successful. 224 * @param fn Filename with full path to be prepended 225 * @param lst The list of recently opened files 226 * @see setupRecentFilesMenu 227 */ 228 void addRecentlyOpenedFile(const QString &fn, QStringList &lst); 229 /*! 230 * @brief checks whether a .qmidiarprc file is present 231 * and creates it with default settings, if not. 232 * @return True if the file existed, False if it was created now. 233 * @see readRcFile, updatePatternPresets 234 * 235 */ 236 bool checkRcFile(); 237 /*! 238 * @brief writes the .qmidiarprc text resource file. 239 * 240 * It is called on program exit and upon modification of the 241 * Arp preset list. 242 * @see readRcFile, updatePatternPresets 243 */ 244 void writeRcFile(); 245 /*! 246 * @brief reads all elements from the .qmidiarprc text 247 * resource file. 248 * 249 * The file contains the Arp preset patterns, the last 250 * GUI state, settings made in the Settings dialog (PassWidget) and 251 * the recent files and path. 252 * This function is called from the MainWindow constructor. 253 * @see readRcFile, updatePatternPresets 254 */ 255 void readRcFile(); 256 /*! 257 * @brief checks if there are no more modules present and sets 258 * some GUI elements accordingly if so. 259 * 260 * It is called by removeArp, removeSeq and removeLfo. 261 * @see checkIfFirstModule 262 */ 263 void checkIfLastModule(); 264 /*! 265 * @brief checks if there were no modules present, i.e. 266 * if the module we just created is the first one, and sets some GUI 267 * elements accordingly if so. 268 * 269 * It is called by addArp, addSeq and addLfo. 270 * @see checkIfLastModule 271 */ 272 void checkIfFirstModule(); 273 /*! 274 * @brief removes and deletes all modules from the 275 * lists. 276 * 277 * It removes all module components, i.e. the Midi workers, UI widgets 278 * and DockWidgets. It disconnects jack transport and stops the 279 * transport if running. 280 */ 281 void clear(); 282 /*! 283 * @brief disables or enables GUI elements depending on 284 * synchronization mode 285 * 286 * It distinguishes between internal and external (MIDI Clock or 287 * JACK Transport) sync. This is necessary since some operations would 288 * break the synchronization, and some others would become useless. 289 * @param on True sets the GUI for external synchronization, False 290 * returns it to internal clock state. 291 * 292 * @see midiClockToggle, jackSyncToggle 293 */ 294 void setGUIforExtSync(bool on); 295 296 /*! @brief Handler for system signals (SIGUSR1, SIGINT...). 297 * This function writes a message to the pipe and leaves as soon as possible 298 */ 299 static void handleSignal(int); 300 /*! @brief sets up a QSocketNotifier forwarding UNIX signals 301 * as Qt signals to provide Ladish L1 support. 302 * 303 * @return True if installation succeeded. 304 */ 305 bool installSignalHandlers(); 306 /*! 307 * @brief allows ignoring one XML element in the XML stream 308 * passed by the caller. 309 * 310 * It also advances the stream read-in. It is used to 311 * ignore unknown elements for both-ways-compatibility 312 * 313 * @param xml reference to QXmlStreamReader containing the open XML stream 314 */ 315 void skipXmlElement(QXmlStreamReader& xml); 316 317 protected: 318 /*! 319 * @brief Handler for close events either by quit or if the user closes 320 * the window. 321 * 322 */ 323 void closeEvent(QCloseEvent*); 324 325 /* PUBLIC MEMBERS */ 326 public: 327 /*! 328 * @param p_portCount Number of registered MIDI output ports 329 * @param p_alsamidi Start as ALSA MIDI client 330 * @param *execName Name of the application's executable 331 */ 332 MainWindow(int p_portCount, bool p_alsamidi, char *execName); 333 ~MainWindow(); 334 335 bool jackFailed; 336 337 /* SIGNALS */ 338 signals: 339 void newTempo(int); 340 #ifdef NSM 341 void nsmOpenFile(const QString & name); 342 #endif 343 344 /* PUBLIC SLOTS */ 345 public slots: 346 /*! 347 * @brief Slot for "New..." UI entries. 348 * 349 * This function calls MainWindow::clear 350 * and empties the current MainWindow::filename. 351 */ 352 void fileNew(); 353 /*! 354 * @brief Slot for "Open..." UI entries. 355 * 356 * This function calls MainWindow::isSave 357 * and MainWindow::chooseFile if all changes are in saved state. 358 */ 359 void fileOpen(); 360 /*! 361 * @brief opens a QMidiArp XML session file for reading 362 * using QXmlStreamReader. 363 * 364 * It queries XML block elements and calls the block readers 365 * MainWindow::readFilePartGlobal, MainWindow::readFilePartModules, 366 * MainWindow::readFilePartGUI. It sets MainWindow::lastDir according to 367 * the file path given with fn and calls MainWindow::updateWindowTitle. 368 * It updates MainWindow::recentFiles list. 369 * 370 * @param fn File name to open including its absolute path 371 */ 372 void openFile(const QString&); 373 /*! 374 * @brief Slot for file Save GUI elements. 375 * 376 * This function calls either 377 * MainWindow::saveFileAs 378 * or MainWindow::saveFile depending on whether the MainWindow::filename is set. 379 * 380 */ 381 void fileSave(); 382 /*! 383 * @brief Slot for file SaveAs GUI elements. 384 * 385 * This function calls saveFileAs. 386 * 387 */ 388 void fileSaveAs(); 389 /*! 390 * @brief Slot for "Add Arpeggiator" menu entry and toolbutton. 391 * 392 * It asks for 393 * the module name and calls MainWindow::addArp with that name. 394 */ 395 void arpNew(); 396 /*! 397 * @brief Slot for "Add LFO" menu entry and toolbutton. 398 * 399 * It asks for 400 * the module name and calls MainWindow::addLfo with that name. 401 */ 402 void lfoNew(); 403 /*! 404 * @brief Slot for "Add Sequencer" menu entry and toolbutton. 405 * 406 * It asks for 407 * the module name and calls MainWindow::addSeq with that name. 408 */ 409 void seqNew(); 410 /*! 411 * @brief removes and deletes an Arpeggiator module. 412 * 413 * It removes all components MidiArp, ArpWidget and 414 * DockWidget from the corresponding lists in Engine. 415 * 416 * @param index The Engine::midiArpList index of the arpeggiator to remove 417 */ 418 void removeArp(int index); 419 /*! 420 * @brief removes and deletes an LFO module. 421 * 422 * It removes all components MidiLfo, LfoWidget and 423 * DockWidget from the corresponding lists in Engine. 424 * 425 * @param index The Engine::midiLfoList index of the LFO to 426 */ 427 void removeLfo(int index); 428 /*! 429 * @brief removes and deletes a Seq module. 430 * 431 * It removes all components MidiSeq, SeqWidget and 432 * DockWidget from the corresponding lists in Engine. 433 * 434 * @param index The Engine::midiSeqList index of the sequencer to remove 435 */ 436 void removeSeq(int index); 437 /*! 438 * @brief duplicates and adds a MidiLfo to the Engine. 439 * 440 * @param ID List ID of the module to copy 441 */ 442 void cloneLfo(int ID); 443 /*! 444 * @brief duplicates and adds a MidiSeq to the Engine. 445 * 446 * @param ID List ID of the module to copy 447 */ 448 void cloneSeq(int ID); 449 450 void helpAbout(); 451 void helpAboutQt(); 452 /*! @brief Slot for tempo spinBox changes. 453 * This function forwards a new tempo value to the driver. 454 * @param tempo The new tempo to be set 455 * 456 */ 457 void updateTempo(int tempo); 458 /*! @brief Slot for Engine::tempoUpdated() signal. 459 * 460 * This function displays a new tempo value in the tempo spin box. 461 * @param p_tempo The new tempo to be displayed 462 * 463 */ 464 void displayTempo(double p_tempo); 465 /*! @brief Slot for MainWindow::runAction ToolButton. 466 * This function calls Engine::setStatus() and disables the 467 * MainWindow::tempoSpin box 468 * @param on True to set Transport to running state 469 * 470 */ 471 void updateTransportStatus(bool on); 472 /*! @brief Slot for midiClock ToolButton. 473 * This function toggles SeqDriver between MIDI Clock and internal clock 474 * operation. 475 * @param on True sets SeqDriver to MIDI Clock operation, false returns to 476 * internal clock. 477 * 478 */ 479 void midiClockToggle(bool on); 480 /*! @brief Slot for jackSync ToolButton. 481 * This function toggles the driver between Jack Transport and internal 482 * clock operation. 483 * @param on True sets driver to JACK Transport operation, false 484 * returns to internal clock. 485 * 486 * @see jackSyncToggle 487 */ 488 void jackSyncToggle(bool on); 489 /*! @brief Slot for the JackDriver::j_shutdown() signal. 490 * This function switches the sync to internal clock operation and 491 * deactivates the Jack Transport Action. 492 * @see jackSyncToggle 493 */ 494 void jackShutdown(); 495 /*! @brief Slot for "Midi Controllers" menu action. This function displays 496 * the MidiCC Dialog window. 497 */ 498 void showMidiCCDialog(); 499 void showIO(); 500 void hideIO(); 501 /*! 502 * @brief appends or deletes an Arp pattern preset. 503 * 504 * If index = 0, it appends an Arp pattern. If index > 0 it deletes 505 * the Arp pattern at index from the list. 506 * It deploys the new pattern preset list to all Arp modules by calling 507 * Engine::updatePatternPresets and writes 508 * the new preset list to the resource file. 509 * This function is a signal slot for ArpWidget::presetsChanged and 510 * called whenever the preset list is modified in one Arp module. 511 * 512 * @param n Name of the preset to append if index = 0 513 * @param p Text sequence of te preset to append if index = 0 514 * @param index List index of the preset to delete or 0 to append a preset 515 * @see ArpWidget::presetsChanged, Engine::updatePatternPresets 516 */ 517 void updatePatternPresets(const QString& n, const QString& p, int index); 518 /*! @brief Slot for fileRecentlyOpenedFiles. 519 * This function proceeds to open the file selected in the recent 520 * files menu. 521 * 522 * @see recentFileActivated, setupRecentFilesMenu 523 */ 524 void recentFileActivated(QAction*); 525 /*! 526 * @brief populates the recent files menu. 527 * 528 * It is called by the constructor MainWindow::MainWindow 529 * @see recentFileActivated, addRecentlyOpenedFile 530 */ 531 void setupRecentFilesMenu(); 532 /*! @brief Slot to give response to an incoming pipe message (Ladish L1). 533 * 534 * This function calls fileSave upon reception of SIGUSR1 and close upon 535 * reception of SIGINT. 536 * @param fd UNIX signal number 537 */ 538 void signalAction(int); 539 540 /*! @brief Slot to give response to an incoming Jack Session event. 541 * 542 * @param ev Type of the event (internal to QMidiarp) 543 */ 544 void jsAction(int ev); 545 void ctb_update_orientation(Qt::Orientation orient); 546 void ftb_update_orientation(Qt::Orientation orient); 547 548 #ifdef NSM 549 static int cb_nsm_open(const char *name, const char *display_name, const char *client_id, char **out_msg, void *userdata); 550 static int cb_nsm_save(char **out_msg, void *userdata); 551 552 int nsm_open(const char *name, const char *display_name, const char *client_id, char **out_msg); 553 int nsm_save(char **out_msg); 554 #endif 555 }; 556 557 #endif 558