| Chris@224 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */ | 
| Chris@224 | 2 | 
| Chris@224 | 3 /* | 
| Chris@224 | 4     Sonic Visualiser | 
| Chris@224 | 5     An audio file viewer and annotation editor. | 
| Chris@224 | 6     Centre for Digital Music, Queen Mary, University of London. | 
| Chris@224 | 7     This file copyright 2006-2007 Chris Cannam and QMUL. | 
| Chris@224 | 8 | 
| Chris@224 | 9     This program is free software; you can redistribute it and/or | 
| Chris@224 | 10     modify it under the terms of the GNU General Public License as | 
| Chris@224 | 11     published by the Free Software Foundation; either version 2 of the | 
| Chris@224 | 12     License, or (at your option) any later version.  See the file | 
| Chris@224 | 13     COPYING included with this distribution for more information. | 
| Chris@224 | 14 */ | 
| Chris@216 | 15 | 
| Chris@216 | 16 #include "MainWindow.h" | 
| Chris@216 | 17 #include "data/osc/OSCQueue.h" | 
| Chris@216 | 18 | 
| Chris@216 | 19 #include "layer/WaveformLayer.h" | 
| Chris@216 | 20 #include "view/ViewManager.h" | 
| Chris@216 | 21 #include "view/Pane.h" | 
| Chris@216 | 22 #include "view/PaneStack.h" | 
| Chris@216 | 23 #include "data/model/WaveFileModel.h" | 
| Chris@248 | 24 #include "widgets/CommandHistory.h" | 
| Chris@1035 | 25 #include "audio/AudioCallbackPlaySource.h" | 
| Chris@216 | 26 #include "framework/Document.h" | 
| Chris@216 | 27 #include "data/fileio/WavFileWriter.h" | 
| Chris@249 | 28 #include "transform/TransformFactory.h" | 
| Chris@1386 | 29 #include "widgets/LevelPanWidget.h" | 
| Chris@1431 | 30 #include "widgets/LevelPanToolButton.h" | 
| Chris@216 | 31 #include "widgets/AudioDial.h" | 
| Chris@216 | 32 | 
| Chris@1035 | 33 #include <bqaudioio/SystemPlaybackTarget.h> | 
| Chris@1035 | 34 | 
| Chris@216 | 35 #include <QFileInfo> | 
| Chris@2441 | 36 #include <QTime> | 
| Chris@2441 | 37 #include <QElapsedTimer> | 
| Chris@2441 | 38 | 
| Chris@2524 | 39 #if (QT_VERSION >= 0x050600) | 
| Chris@2441 | 40 #define NOW (QTime::currentTime().toString(Qt::ISODateWithMs)) | 
| Chris@2524 | 41 #else | 
| Chris@2524 | 42 #define NOW (QTime::currentTime().toString(Qt::ISODate)) | 
| Chris@2524 | 43 #endif | 
| Chris@216 | 44 | 
| Chris@216 | 45 void | 
| Chris@216 | 46 MainWindow::handleOSCMessage(const OSCMessage &message) | 
| Chris@216 | 47 { | 
| Chris@2441 | 48     QElapsedTimer timer; | 
| Chris@2441 | 49     timer.start(); | 
| Chris@2441 | 50 | 
| Chris@2441 | 51     SVDEBUG << "OSCHandler at " << NOW << ": handling message: " | 
| Chris@2441 | 52             << message.toString() << endl; | 
| Chris@216 | 53 | 
| Chris@216 | 54     if (message.getMethod() == "open") { | 
| Chris@216 | 55 | 
| Chris@216 | 56         if (message.getArgCount() == 1 && | 
| Chris@216 | 57             message.getArg(0).canConvert(QVariant::String)) { | 
| Chris@216 | 58             QString path = message.getArg(0).toString(); | 
| Chris@2441 | 59             if (open(path, ReplaceMainModel) == FileOpenSucceeded) { | 
| Chris@2441 | 60                 SVDEBUG << "OSCHandler: Opened path \"" | 
| Chris@2441 | 61                         << path << "\"" << endl; | 
| Chris@2441 | 62             } else { | 
| Chris@2441 | 63                 SVCERR << "OSCHandler: File open failed for path \"" | 
| Chris@2441 | 64                        << path << "\"" << endl; | 
| Chris@216 | 65             } | 
| Chris@216 | 66             //!!! we really need to spin here and not return until the | 
| Chris@216 | 67             // file has been completely decoded... | 
| Chris@2519 | 68         } else { | 
| Chris@2519 | 69             SVCERR << "OSCHandler: Usage: /open <filename>" << endl; | 
| Chris@216 | 70         } | 
| Chris@216 | 71 | 
| Chris@216 | 72     } else if (message.getMethod() == "openadditional") { | 
| Chris@216 | 73 | 
| Chris@216 | 74         if (message.getArgCount() == 1 && | 
| Chris@216 | 75             message.getArg(0).canConvert(QVariant::String)) { | 
| Chris@216 | 76             QString path = message.getArg(0).toString(); | 
| Chris@2441 | 77             if (open(path, CreateAdditionalModel) == FileOpenSucceeded) { | 
| Chris@2441 | 78                 SVDEBUG << "OSCHandler: Opened additional path \"" | 
| Chris@2441 | 79                         << path << "\"" << endl; | 
| Chris@2441 | 80             } else { | 
| Chris@2441 | 81                 SVCERR << "OSCHandler: File open failed for path \"" | 
| Chris@665 | 82                           << path << "\"" << endl; | 
| Chris@216 | 83             } | 
| Chris@2519 | 84         } else { | 
| Chris@2519 | 85             SVCERR << "OSCHandler: Usage: /openadditional <filename>" << endl; | 
| Chris@216 | 86         } | 
| Chris@216 | 87 | 
| Chris@216 | 88     } else if (message.getMethod() == "recent" || | 
| Chris@216 | 89                message.getMethod() == "last") { | 
| Chris@216 | 90 | 
| Chris@216 | 91         int n = 0; | 
| Chris@216 | 92         if (message.getMethod() == "recent" && | 
| Chris@216 | 93             message.getArgCount() == 1 && | 
| Chris@216 | 94             message.getArg(0).canConvert(QVariant::Int)) { | 
| Chris@216 | 95             n = message.getArg(0).toInt() - 1; | 
| Chris@216 | 96         } | 
| Chris@216 | 97         std::vector<QString> recent = m_recentFiles.getRecent(); | 
| Chris@216 | 98         if (n >= 0 && n < int(recent.size())) { | 
| Chris@2441 | 99             QString path = recent[n]; | 
| Chris@2441 | 100             if (open(path, ReplaceMainModel) == FileOpenSucceeded) { | 
| Chris@2441 | 101                 SVDEBUG << "OSCHandler: Opened recent path \"" | 
| Chris@2441 | 102                         << path << "\"" << endl; | 
| Chris@2441 | 103             } else { | 
| Chris@2441 | 104                 SVCERR << "OSCHandler: File open failed for path \"" | 
| Chris@2441 | 105                        << path << "\"" << endl; | 
| Chris@216 | 106             } | 
| Chris@2519 | 107         } else { | 
| Chris@2519 | 108             SVCERR << "OSCHandler: Usage: /recent <n>" << endl; | 
| Chris@2519 | 109             SVCERR << "               or  /last" << endl; | 
| Chris@216 | 110         } | 
| Chris@216 | 111 | 
| Chris@216 | 112     } else if (message.getMethod() == "save") { | 
| Chris@216 | 113 | 
| Chris@216 | 114         QString path; | 
| Chris@216 | 115         if (message.getArgCount() == 1 && | 
| Chris@216 | 116             message.getArg(0).canConvert(QVariant::String)) { | 
| Chris@216 | 117             path = message.getArg(0).toString(); | 
| Chris@216 | 118             if (QFileInfo(path).exists()) { | 
| Chris@2441 | 119                 SVCERR << "OSCHandler: Refusing to overwrite existing file in save" << endl; | 
| Chris@2441 | 120             } else if (saveSessionFile(path)) { | 
| Chris@2441 | 121                 SVDEBUG << "OSCHandler: Saved session to path \"" | 
| Chris@2441 | 122                         << path << "\"" << endl; | 
| Chris@216 | 123             } else { | 
| Chris@2441 | 124                 SVCERR << "OSCHandler: Save failed to path \"" | 
| Chris@2441 | 125                        << path << "\"" << endl; | 
| Chris@216 | 126             } | 
| Chris@2519 | 127         } else { | 
| Chris@2519 | 128             SVCERR << "OSCHandler: Usage: /save <filename>" << endl; | 
| Chris@216 | 129         } | 
| Chris@216 | 130 | 
| Chris@216 | 131     } else if (message.getMethod() == "export") { | 
| Chris@216 | 132 | 
| Chris@216 | 133         QString path; | 
| Chris@216 | 134         if (getMainModel()) { | 
| Chris@216 | 135             if (message.getArgCount() == 1 && | 
| Chris@216 | 136                 message.getArg(0).canConvert(QVariant::String)) { | 
| Chris@216 | 137                 path = message.getArg(0).toString(); | 
| Chris@216 | 138                 if (QFileInfo(path).exists()) { | 
| Chris@2441 | 139                     SVCERR << "OSCHandler: Refusing to overwrite existing file in export" << endl; | 
| Chris@216 | 140                 } else { | 
| Chris@216 | 141                     WavFileWriter writer(path, | 
| Chris@216 | 142                                          getMainModel()->getSampleRate(), | 
| Chris@428 | 143                                          getMainModel()->getChannelCount(), | 
| Chris@428 | 144                                          WavFileWriter::WriteToTemporary); | 
| Chris@216 | 145                     MultiSelection ms = m_viewManager->getSelection(); | 
| Chris@2441 | 146                     if (writer.writeModel | 
| Chris@2441 | 147                         (getMainModel().get(), | 
| Chris@2441 | 148                          ms.getSelections().empty() ? nullptr : &ms)) { | 
| Chris@2441 | 149                         SVDEBUG << "OSCHandler: Exported audio to path \"" | 
| Chris@2441 | 150                                 << path << "\"" << endl; | 
| Chris@216 | 151                     } else { | 
| Chris@2441 | 152                         SVCERR << "OSCHandler: Export failed to path \"" | 
| Chris@2441 | 153                                << path << "\"" << endl; | 
| Chris@216 | 154                     } | 
| Chris@216 | 155                 } | 
| Chris@216 | 156             } | 
| Chris@2519 | 157         } else { | 
| Chris@2519 | 158             SVCERR << "OSCHandler: Usage: /export <filename>" << endl; | 
| Chris@216 | 159         } | 
| Chris@216 | 160 | 
| Chris@2242 | 161     } else if (message.getMethod() == "exportlayer") { | 
| Chris@2242 | 162 | 
| Chris@2242 | 163         QString path; | 
| Chris@2242 | 164         if (message.getArgCount() == 1 && | 
| Chris@2242 | 165             message.getArg(0).canConvert(QVariant::String)) { | 
| Chris@2242 | 166             path = message.getArg(0).toString(); | 
| Chris@2242 | 167             if (QFileInfo(path).exists()) { | 
| Chris@2519 | 168                 SVCERR << "OSCHandler: Refusing to overwrite existing file in layer export" << endl; | 
| Chris@2242 | 169             } else { | 
| Chris@2242 | 170                 Pane *currentPane = nullptr; | 
| Chris@2242 | 171                 Layer *currentLayer = nullptr; | 
| Chris@2242 | 172                 if (m_paneStack) currentPane = m_paneStack->getCurrentPane(); | 
| Chris@2242 | 173                 if (currentPane) currentLayer = currentPane->getSelectedLayer(); | 
| Chris@2442 | 174                 MultiSelection ms = m_viewManager->getSelection(); | 
| Chris@2242 | 175                 if (currentLayer) { | 
| Chris@2242 | 176                     QString error; | 
| Chris@2442 | 177                     if (exportLayerTo | 
| Chris@2442 | 178                         (currentLayer, currentPane, | 
| Chris@2442 | 179                          ms.getSelections().empty() ? nullptr : &ms, | 
| Chris@2442 | 180                          path, error)) { | 
| Chris@2442 | 181                         SVDEBUG << "OSCHandler: Exported layer \"" | 
| Chris@2442 | 182                                 << currentLayer->getLayerPresentationName() | 
| Chris@2442 | 183                                 << "\" to path \"" << path << "\"" << endl; | 
| Chris@2442 | 184                     } else { | 
| Chris@2442 | 185                         SVCERR << "OSCHandler: Export failed to path \"" | 
| Chris@2442 | 186                                << path << "\"" << endl; | 
| Chris@2242 | 187                     } | 
| Chris@2242 | 188                 } else { | 
| Chris@2242 | 189                     SVCERR << "OSCHandler: No current layer to export" << endl; | 
| Chris@2242 | 190                 } | 
| Chris@2242 | 191             } | 
| Chris@2519 | 192         } else { | 
| Chris@2519 | 193             SVCERR << "OSCHandler: Usage: /exportlayer <filename>" << endl; | 
| Chris@2519 | 194         } | 
| Chris@2519 | 195 | 
| Chris@2519 | 196     } else if (message.getMethod() == "exportimage") { | 
| Chris@2519 | 197 | 
| Chris@2519 | 198         QString path; | 
| Chris@2519 | 199         if (message.getArgCount() == 1 && | 
| Chris@2519 | 200             message.getArg(0).canConvert(QVariant::String)) { | 
| Chris@2519 | 201             path = message.getArg(0).toString(); | 
| Chris@2519 | 202             if (QFileInfo(path).exists()) { | 
| Chris@2519 | 203                 SVCERR << "OSCHandler: Refusing to overwrite existing file in image export" << endl; | 
| Chris@2519 | 204             } else { | 
| Chris@2519 | 205                 Pane *currentPane = nullptr; | 
| Chris@2519 | 206                 if (m_paneStack) currentPane = m_paneStack->getCurrentPane(); | 
| Chris@2519 | 207                 MultiSelection ms = m_viewManager->getSelection(); | 
| Chris@2519 | 208                 if (currentPane) { | 
| Chris@2519 | 209                     QImage *image = nullptr; | 
| Chris@2519 | 210                     auto sel = ms.getSelections(); | 
| Chris@2519 | 211                     if (!sel.empty()) { | 
| Chris@2519 | 212                         sv_frame_t sf0 = sel.begin()->getStartFrame(); | 
| Chris@2519 | 213                         sv_frame_t sf1 = sel.rbegin()->getEndFrame(); | 
| Chris@2519 | 214                         image = currentPane->renderPartToNewImage(sf0, sf1); | 
| Chris@2519 | 215                     } else { | 
| Chris@2519 | 216                         image = currentPane->renderToNewImage(); | 
| Chris@2519 | 217                     } | 
| Chris@2519 | 218                     if (!image) { | 
| Chris@2519 | 219                         SVCERR << "OSCHandler: Failed to create image from pane" | 
| Chris@2519 | 220                                << endl; | 
| Chris@2519 | 221                     } else if (!image->save(path, "PNG")) { | 
| Chris@2519 | 222                         SVCERR << "OSCHandler: Export failed to image file \"" | 
| Chris@2519 | 223                                << path << "\"" << endl; | 
| Chris@2519 | 224                     } else { | 
| Chris@2519 | 225                         SVDEBUG << "OSCHandler: Exported pane to image file \"" | 
| Chris@2519 | 226                                << path << "\"" << endl; | 
| Chris@2519 | 227                     } | 
| Chris@2519 | 228                     delete image; | 
| Chris@2519 | 229                 } else { | 
| Chris@2519 | 230                     SVCERR << "OSCHandler: No current pane to export" << endl; | 
| Chris@2519 | 231                 } | 
| Chris@2519 | 232             } | 
| Chris@2519 | 233         } else { | 
| Chris@2519 | 234             SVCERR << "OSCHandler: Usage: /exportimage <filename>" << endl; | 
| Chris@2519 | 235         } | 
| Chris@2519 | 236 | 
| Chris@2519 | 237     } else if (message.getMethod() == "exportsvg") { | 
| Chris@2519 | 238 | 
| Chris@2519 | 239         QString path; | 
| Chris@2519 | 240         if (message.getArgCount() == 1 && | 
| Chris@2519 | 241             message.getArg(0).canConvert(QVariant::String)) { | 
| Chris@2519 | 242             path = message.getArg(0).toString(); | 
| Chris@2519 | 243             if (QFileInfo(path).exists()) { | 
| Chris@2519 | 244                 SVCERR << "OSCHandler: Refusing to overwrite existing file in SVG export" << endl; | 
| Chris@2519 | 245             } else { | 
| Chris@2519 | 246                 Pane *currentPane = nullptr; | 
| Chris@2519 | 247                 if (m_paneStack) currentPane = m_paneStack->getCurrentPane(); | 
| Chris@2519 | 248                 MultiSelection ms = m_viewManager->getSelection(); | 
| Chris@2519 | 249                 if (currentPane) { | 
| Chris@2519 | 250                     bool result = false; | 
| Chris@2519 | 251                     auto sel = ms.getSelections(); | 
| Chris@2519 | 252                     if (!sel.empty()) { | 
| Chris@2519 | 253                         sv_frame_t sf0 = sel.begin()->getStartFrame(); | 
| Chris@2519 | 254                         sv_frame_t sf1 = sel.rbegin()->getEndFrame(); | 
| Chris@2519 | 255                         result = currentPane->renderPartToSvgFile(path, sf0, sf1); | 
| Chris@2519 | 256                     } else { | 
| Chris@2519 | 257                         result = currentPane->renderToSvgFile(path); | 
| Chris@2519 | 258                     } | 
| Chris@2519 | 259                     if (!result) { | 
| Chris@2519 | 260                         SVCERR << "OSCHandler: Export failed to SVG file \"" | 
| Chris@2519 | 261                                << path << "\"" << endl; | 
| Chris@2519 | 262                     } else { | 
| Chris@2519 | 263                         SVDEBUG << "OSCHandler: Exported pane to SVG file \"" | 
| Chris@2519 | 264                                 << path << "\"" << endl; | 
| Chris@2519 | 265                     } | 
| Chris@2519 | 266                 } else { | 
| Chris@2519 | 267                     SVCERR << "OSCHandler: No current pane to export" << endl; | 
| Chris@2519 | 268                 } | 
| Chris@2519 | 269             } | 
| Chris@2519 | 270         } else { | 
| Chris@2519 | 271             SVCERR << "OSCHandler: Usage: /exportsvg <filename>" << endl; | 
| Chris@2242 | 272         } | 
| Chris@2242 | 273 | 
| Chris@216 | 274     } else if (message.getMethod() == "jump" || | 
| Chris@216 | 275                message.getMethod() == "play") { | 
| Chris@216 | 276 | 
| Chris@216 | 277         if (getMainModel()) { | 
| Chris@216 | 278 | 
| Chris@922 | 279             sv_frame_t frame = m_viewManager->getPlaybackFrame(); | 
| Chris@216 | 280             bool selection = false; | 
| Chris@216 | 281             bool play = (message.getMethod() == "play"); | 
| Chris@216 | 282 | 
| Chris@216 | 283             if (message.getArgCount() == 1) { | 
| Chris@216 | 284 | 
| Chris@216 | 285                 if (message.getArg(0).canConvert(QVariant::String) && | 
| Chris@216 | 286                     message.getArg(0).toString() == "selection") { | 
| Chris@216 | 287 | 
| Chris@216 | 288                     selection = true; | 
| Chris@216 | 289 | 
| Chris@216 | 290                 } else if (message.getArg(0).canConvert(QVariant::String) && | 
| Chris@216 | 291                            message.getArg(0).toString() == "end") { | 
| Chris@216 | 292 | 
| Chris@216 | 293                     frame = getMainModel()->getEndFrame(); | 
| Chris@216 | 294 | 
| Chris@216 | 295                 } else if (message.getArg(0).canConvert(QVariant::Double)) { | 
| Chris@216 | 296 | 
| Chris@216 | 297                     double time = message.getArg(0).toDouble(); | 
| Chris@216 | 298                     if (time < 0.0) time = 0.0; | 
| Chris@216 | 299 | 
| Chris@216 | 300                     frame = lrint(time * getMainModel()->getSampleRate()); | 
| Chris@216 | 301                 } | 
| Chris@216 | 302             } | 
| Chris@216 | 303 | 
| Chris@216 | 304             if (frame > getMainModel()->getEndFrame()) { | 
| Chris@216 | 305                 frame = getMainModel()->getEndFrame(); | 
| Chris@216 | 306             } | 
| Chris@216 | 307 | 
| Chris@216 | 308             if (play) { | 
| Chris@216 | 309                 m_viewManager->setPlaySelectionMode(selection); | 
| Chris@216 | 310             } | 
| Chris@216 | 311 | 
| Chris@216 | 312             if (selection) { | 
| Chris@216 | 313                 MultiSelection::SelectionList sl = m_viewManager->getSelections(); | 
| Chris@216 | 314                 if (!sl.empty()) { | 
| Chris@216 | 315                     frame = sl.begin()->getStartFrame(); | 
| Chris@216 | 316                 } | 
| Chris@216 | 317             } | 
| Chris@216 | 318 | 
| Chris@1617 | 319             SVDEBUG << "OSCHandler: Setting playback frame to " << frame << endl; | 
| Chris@1617 | 320 | 
| Chris@216 | 321             m_viewManager->setPlaybackFrame(frame); | 
| Chris@216 | 322 | 
| Chris@1617 | 323             if (play) { | 
| Chris@1617 | 324                 if (!m_playSource->isPlaying()) { | 
| Chris@1617 | 325                     SVDEBUG << "OSCHandler: Play source is not yet playing, calling play()" << endl; | 
| Chris@1617 | 326                     // handles audio device suspend/resume etc, as | 
| Chris@1617 | 327                     // well as calling m_playSource->play(frame) | 
| Chris@1617 | 328                     MainWindow::play(); | 
| Chris@1617 | 329                 } else { | 
| Chris@1617 | 330                     SVDEBUG << "OSCHandler: Play source is already playing, not starting it" << endl; | 
| Chris@1617 | 331                 } | 
| Chris@1617 | 332             } else { | 
| Chris@1617 | 333                 SVDEBUG << "OSCHandler: Jump only requested, not starting playback" << endl; | 
| Chris@216 | 334             } | 
| Chris@216 | 335         } | 
| Chris@216 | 336 | 
| Chris@313 | 337     } else if (message.getMethod() == "ffwd") { | 
| Chris@313 | 338 | 
| Chris@313 | 339         if (message.getArgCount() == 1) { | 
| Chris@313 | 340 | 
| Chris@313 | 341             if (message.getArg(0).canConvert(QVariant::String) && | 
| Chris@313 | 342                 message.getArg(0).toString() == "similar") { | 
| Chris@313 | 343 | 
| Chris@2441 | 344                 SVDEBUG << "OSCHandler: Calling ffwdSimilar" << endl; | 
| Chris@313 | 345                 ffwdSimilar(); | 
| Chris@313 | 346             } | 
| Chris@313 | 347         } else { | 
| Chris@313 | 348 | 
| Chris@2441 | 349             SVDEBUG << "OSCHandler: Calling ffwd" << endl; | 
| Chris@313 | 350             ffwd(); | 
| Chris@313 | 351         } | 
| Chris@313 | 352 | 
| Chris@313 | 353     } else if (message.getMethod() == "rewind") { | 
| Chris@313 | 354 | 
| Chris@313 | 355         if (message.getArgCount() == 1) { | 
| Chris@313 | 356 | 
| Chris@313 | 357             if (message.getArg(0).canConvert(QVariant::String) && | 
| Chris@313 | 358                 message.getArg(0).toString() == "similar") { | 
| Chris@313 | 359 | 
| Chris@2441 | 360                 SVDEBUG << "OSCHandler: Calling rewindSimilar" << endl; | 
| Chris@313 | 361                 rewindSimilar(); | 
| Chris@313 | 362             } | 
| Chris@313 | 363         } else { | 
| Chris@313 | 364 | 
| Chris@2441 | 365             SVDEBUG << "OSCHandler: Calling rewind" << endl; | 
| Chris@313 | 366             rewind(); | 
| Chris@313 | 367         } | 
| Chris@313 | 368 | 
| Chris@216 | 369     } else if (message.getMethod() == "stop") { | 
| Chris@216 | 370 | 
| Chris@2441 | 371         if (m_playSource->isPlaying()) { | 
| Chris@2441 | 372             // As with play, we want to use the MainWindow function | 
| Chris@2441 | 373             // rather than call m_playSource directly because that way | 
| Chris@2441 | 374             // the audio driver suspend/resume etc is handled properly | 
| Chris@2441 | 375             SVDEBUG << "OSCHandler: Calling stop" << endl; | 
| Chris@2441 | 376             MainWindow::stop(); | 
| Chris@2441 | 377         } else { | 
| Chris@2441 | 378             SVDEBUG << "OSCHandler: Not playing, doing nothing" << endl; | 
| Chris@2441 | 379         } | 
| Chris@216 | 380 | 
| Chris@216 | 381     } else if (message.getMethod() == "loop") { | 
| Chris@216 | 382 | 
| Chris@216 | 383         if (message.getArgCount() == 1 && | 
| Chris@216 | 384             message.getArg(0).canConvert(QVariant::String)) { | 
| Chris@216 | 385 | 
| Chris@216 | 386             QString str = message.getArg(0).toString(); | 
| Chris@216 | 387             if (str == "on") { | 
| Chris@2441 | 388                 SVDEBUG << "OSCHandler: Enabling loop mode" << endl; | 
| Chris@216 | 389                 m_viewManager->setPlayLoopMode(true); | 
| Chris@216 | 390             } else if (str == "off") { | 
| Chris@2441 | 391                 SVDEBUG << "OSCHandler: Disabling loop mode" << endl; | 
| Chris@216 | 392                 m_viewManager->setPlayLoopMode(false); | 
| Chris@216 | 393             } | 
| Chris@216 | 394         } | 
| Chris@216 | 395 | 
| Chris@216 | 396     } else if (message.getMethod() == "solo") { | 
| Chris@216 | 397 | 
| Chris@216 | 398         if (message.getArgCount() == 1 && | 
| Chris@216 | 399             message.getArg(0).canConvert(QVariant::String)) { | 
| Chris@216 | 400 | 
| Chris@216 | 401             QString str = message.getArg(0).toString(); | 
| Chris@216 | 402             if (str == "on") { | 
| Chris@2441 | 403                 SVDEBUG << "OSCHandler: Enabling solo mode" << endl; | 
| Chris@216 | 404                 m_viewManager->setPlaySoloMode(true); | 
| Chris@216 | 405             } else if (str == "off") { | 
| Chris@2441 | 406                 SVDEBUG << "OSCHandler: Disabling solo mode" << endl; | 
| Chris@216 | 407                 m_viewManager->setPlaySoloMode(false); | 
| Chris@216 | 408             } | 
| Chris@216 | 409         } | 
| Chris@216 | 410 | 
| Chris@216 | 411     } else if (message.getMethod() == "select" || | 
| Chris@216 | 412                message.getMethod() == "addselect") { | 
| Chris@216 | 413 | 
| Chris@216 | 414         if (getMainModel()) { | 
| Chris@216 | 415 | 
| Chris@920 | 416             sv_frame_t f0 = getMainModel()->getStartFrame(); | 
| Chris@920 | 417             sv_frame_t f1 = getMainModel()->getEndFrame(); | 
| Chris@216 | 418 | 
| Chris@216 | 419             bool done = false; | 
| Chris@216 | 420 | 
| Chris@216 | 421             if (message.getArgCount() == 2 && | 
| Chris@216 | 422                 message.getArg(0).canConvert(QVariant::Double) && | 
| Chris@216 | 423                 message.getArg(1).canConvert(QVariant::Double)) { | 
| Chris@216 | 424 | 
| Chris@216 | 425                 double t0 = message.getArg(0).toDouble(); | 
| Chris@216 | 426                 double t1 = message.getArg(1).toDouble(); | 
| Chris@216 | 427                 if (t1 < t0) { double temp = t0; t0 = t1; t1 = temp; } | 
| Chris@216 | 428                 if (t0 < 0.0) t0 = 0.0; | 
| Chris@216 | 429                 if (t1 < 0.0) t1 = 0.0; | 
| Chris@216 | 430 | 
| Chris@216 | 431                 f0 = lrint(t0 * getMainModel()->getSampleRate()); | 
| Chris@216 | 432                 f1 = lrint(t1 * getMainModel()->getSampleRate()); | 
| Chris@2441 | 433 | 
| Chris@2441 | 434                 SVDEBUG << "OSCHandler: Converted selection extents to frames " | 
| Chris@2441 | 435                         << f0 << " and " << f1 << endl; | 
| Chris@216 | 436 | 
| Chris@216 | 437                 Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@2126 | 438                 Layer *layer = nullptr; | 
| Chris@216 | 439                 if (pane) layer = pane->getSelectedLayer(); | 
| Chris@216 | 440                 if (layer) { | 
| Chris@730 | 441                     int resolution; | 
| Chris@216 | 442                     layer->snapToFeatureFrame(pane, f0, resolution, | 
| Chris@2380 | 443                                               Layer::SnapLeft, -1); | 
| Chris@216 | 444                     layer->snapToFeatureFrame(pane, f1, resolution, | 
| Chris@2380 | 445                                               Layer::SnapRight, -1); | 
| Chris@2441 | 446 | 
| Chris@2441 | 447                     SVDEBUG << "OSCHandler: Snapped selection extents to " | 
| Chris@2441 | 448                             << f0 << " and " << f1 << " for current layer \"" | 
| Chris@2441 | 449                             << layer->getLayerPresentationName() << "\"" | 
| Chris@2441 | 450                             << endl; | 
| Chris@216 | 451                 } | 
| Chris@216 | 452 | 
| Chris@216 | 453             } else if (message.getArgCount() == 1 && | 
| Chris@216 | 454                        message.getArg(0).canConvert(QVariant::String)) { | 
| Chris@2519 | 455 | 
| Chris@216 | 456                 QString str = message.getArg(0).toString(); | 
| Chris@216 | 457                 if (str == "none") { | 
| Chris@2441 | 458                     SVDEBUG << "OSCHandler: Clearing selection" << endl; | 
| Chris@216 | 459                     m_viewManager->clearSelections(); | 
| Chris@216 | 460                     done = true; | 
| Chris@2441 | 461                 } else if (str == "all") { | 
| Chris@2441 | 462                     SVDEBUG << "OSCHandler: Selecting all" << endl; | 
| Chris@2441 | 463                     f0 = getModelsStartFrame(); | 
| Chris@2441 | 464                     f0 = getModelsEndFrame(); | 
| Chris@216 | 465                 } | 
| Chris@216 | 466             } | 
| Chris@216 | 467 | 
| Chris@216 | 468             if (!done) { | 
| Chris@216 | 469                 if (message.getMethod() == "select") { | 
| Chris@216 | 470                     m_viewManager->setSelection(Selection(f0, f1)); | 
| Chris@216 | 471                 } else { | 
| Chris@216 | 472                     m_viewManager->addSelection(Selection(f0, f1)); | 
| Chris@216 | 473                 } | 
| Chris@216 | 474             } | 
| Chris@2441 | 475 | 
| Chris@2441 | 476             SVDEBUG << "OSCHandler: Selection now is " | 
| Chris@2441 | 477                     << m_viewManager->getSelection().toString() << endl; | 
| Chris@2441 | 478 | 
| Chris@2441 | 479         } else { | 
| Chris@2441 | 480             SVCERR << "OSCHandler: No main model, can't modify selection" | 
| Chris@2441 | 481                    << endl; | 
| Chris@216 | 482         } | 
| Chris@216 | 483 | 
| Chris@216 | 484     } else if (message.getMethod() == "add") { | 
| Chris@216 | 485 | 
| Chris@216 | 486         if (getMainModel()) { | 
| Chris@216 | 487 | 
| Chris@216 | 488             if (message.getArgCount() >= 1 && | 
| Chris@216 | 489                 message.getArg(0).canConvert(QVariant::String)) { | 
| Chris@216 | 490 | 
| Chris@216 | 491                 int channel = -1; | 
| Chris@216 | 492                 if (message.getArgCount() == 2 && | 
| Chris@216 | 493                     message.getArg(0).canConvert(QVariant::Int)) { | 
| Chris@216 | 494                     channel = message.getArg(0).toInt(); | 
| Chris@216 | 495                     if (channel < -1 || | 
| Chris@2519 | 496                         channel >= int(getMainModel()->getChannelCount())) { | 
| Chris@2519 | 497                         SVCERR << "OSCHandler: channel " << channel | 
| Chris@2519 | 498                                << " out of range (0 to " | 
| Chris@2519 | 499                                << (getMainModel()->getChannelCount() - 1) | 
| Chris@2519 | 500                                << ")" << endl; | 
| Chris@216 | 501                         channel = -1; | 
| Chris@216 | 502                     } | 
| Chris@216 | 503                 } | 
| Chris@216 | 504 | 
| Chris@216 | 505                 QString str = message.getArg(0).toString(); | 
| Chris@216 | 506 | 
| Chris@216 | 507                 LayerFactory::LayerType type = | 
| Chris@216 | 508                     LayerFactory::getInstance()->getLayerTypeForName(str); | 
| Chris@216 | 509 | 
| Chris@216 | 510                 if (type == LayerFactory::UnknownLayer) { | 
| Chris@2441 | 511                     SVCERR << "WARNING: OSCHandler: unknown layer " | 
| Chris@2441 | 512                            << "type " << str << endl; | 
| Chris@216 | 513                 } else { | 
| Chris@216 | 514 | 
| Chris@232 | 515                     LayerConfiguration configuration(type, | 
| Chris@2300 | 516                                                      getMainModelId(), | 
| Chris@232 | 517                                                      channel); | 
| Chris@2441 | 518 | 
| Chris@2441 | 519                     QString pname = LayerFactory::getInstance()-> | 
| Chris@2441 | 520                         getLayerPresentationName(type); | 
| Chris@216 | 521 | 
| Chris@2441 | 522                     addPane(configuration, tr("Add %1 Pane") .arg(pname)); | 
| Chris@2441 | 523 | 
| Chris@2441 | 524                     SVDEBUG << "OSCHandler: Added pane \"" << pname | 
| Chris@2441 | 525                             << "\"" << endl; | 
| Chris@216 | 526                 } | 
| Chris@2519 | 527             } else { | 
| Chris@2519 | 528                 SVCERR << "OSCHandler: Usage: /add <layertype> [<channel>]" | 
| Chris@2519 | 529                        << endl; | 
| Chris@216 | 530             } | 
| Chris@216 | 531         } | 
| Chris@216 | 532 | 
| Chris@216 | 533     } else if (message.getMethod() == "undo") { | 
| Chris@216 | 534 | 
| Chris@2441 | 535         SVDEBUG << "OSCHandler: Calling undo" << endl; | 
| Chris@216 | 536         CommandHistory::getInstance()->undo(); | 
| Chris@216 | 537 | 
| Chris@216 | 538     } else if (message.getMethod() == "redo") { | 
| Chris@216 | 539 | 
| Chris@2441 | 540         SVDEBUG << "OSCHandler: Calling redo" << endl; | 
| Chris@216 | 541         CommandHistory::getInstance()->redo(); | 
| Chris@216 | 542 | 
| Chris@216 | 543     } else if (message.getMethod() == "set") { | 
| Chris@216 | 544 | 
| Chris@216 | 545         if (message.getArgCount() == 2 && | 
| Chris@216 | 546             message.getArg(0).canConvert(QVariant::String) && | 
| Chris@216 | 547             message.getArg(1).canConvert(QVariant::Double)) { | 
| Chris@216 | 548 | 
| Chris@216 | 549             QString property = message.getArg(0).toString(); | 
| Chris@216 | 550             float value = (float)message.getArg(1).toDouble(); | 
| Chris@216 | 551 | 
| Chris@216 | 552             if (property == "gain") { | 
| Chris@216 | 553                 if (value < 0.0) value = 0.0; | 
| Chris@1386 | 554                 m_mainLevelPan->setLevel(value); | 
| Chris@216 | 555                 if (m_playTarget) m_playTarget->setOutputGain(value); | 
| Chris@1617 | 556             } else if (property == "speed") { | 
| Chris@1617 | 557                 m_playSpeed->setMappedValue(value); | 
| Chris@216 | 558             } else if (property == "speedup") { | 
| Chris@1617 | 559 | 
| Chris@1617 | 560                 // The speedup method existed before the speed method | 
| Chris@1617 | 561                 // and is a bit weirder. | 
| Chris@1617 | 562                 // | 
| Chris@1617 | 563                 // For speed(x), x is a percentage of normal speed, so | 
| Chris@1617 | 564                 // x=100 means play at the normal speed, x=50 means | 
| Chris@1617 | 565                 // half speed, x=200 double speed etc. | 
| Chris@1617 | 566                 // | 
| Chris@1617 | 567                 // For speedup(x), x was some sort of modifier of | 
| Chris@1617 | 568                 // percentage thing, so x=0 meant play at the normal | 
| Chris@1617 | 569                 // speed, x=50 meant play at 150% of normal speed, | 
| Chris@1617 | 570                 // x=100 meant play at double speed, and x=-100 rather | 
| Chris@1617 | 571                 // bizarrely meant play at half speed. We handle this | 
| Chris@1617 | 572                 // now by converting to speed percentage as follows: | 
| Chris@1617 | 573 | 
| Chris@1617 | 574                 double percentage = 100.0; | 
| Chris@1617 | 575                 if (value > 0.f) { | 
| Chris@1617 | 576                     percentage = percentage + value; | 
| Chris@1617 | 577                 } else { | 
| Chris@1617 | 578                     percentage = 10000.0 / (percentage - value); | 
| Chris@1617 | 579                 } | 
| Chris@1617 | 580                 SVDEBUG << "OSCHandler: converted speedup(" << value | 
| Chris@1617 | 581                         << ") into speed(" << percentage << ")" << endl; | 
| Chris@1617 | 582 | 
| Chris@1617 | 583                 m_playSpeed->setMappedValue(percentage); | 
| Chris@1617 | 584 | 
| Chris@216 | 585             } else if (property == "overlays") { | 
| Chris@216 | 586                 if (value < 0.5) { | 
| Chris@216 | 587                     m_viewManager->setOverlayMode(ViewManager::NoOverlays); | 
| Chris@216 | 588                 } else if (value < 1.5) { | 
| Chris@701 | 589                     m_viewManager->setOverlayMode(ViewManager::StandardOverlays); | 
| Chris@216 | 590                 } else { | 
| Chris@216 | 591                     m_viewManager->setOverlayMode(ViewManager::AllOverlays); | 
| Chris@216 | 592                 } | 
| Chris@216 | 593             } else if (property == "zoomwheels") { | 
| Chris@216 | 594                 m_viewManager->setZoomWheelsEnabled(value > 0.5); | 
| Chris@216 | 595             } else if (property == "propertyboxes") { | 
| Chris@216 | 596                 bool toggle = ((value < 0.5) != | 
| Chris@2339 | 597                                (m_paneStack->getLayoutStyle() == | 
| Chris@2339 | 598                                 PaneStack::HiddenPropertyStacksLayout)); | 
| Chris@216 | 599                 if (toggle) togglePropertyBoxes(); | 
| Chris@216 | 600             } | 
| Chris@216 | 601 | 
| Chris@216 | 602         } else { | 
| Chris@2126 | 603             PropertyContainer *container = nullptr; | 
| Chris@216 | 604             Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@216 | 605             if (pane && | 
| Chris@216 | 606                 message.getArgCount() == 3 && | 
| Chris@216 | 607                 message.getArg(0).canConvert(QVariant::String) && | 
| Chris@216 | 608                 message.getArg(1).canConvert(QVariant::String) && | 
| Chris@216 | 609                 message.getArg(2).canConvert(QVariant::String)) { | 
| Chris@216 | 610                 if (message.getArg(0).toString() == "pane") { | 
| Chris@216 | 611                     container = pane->getPropertyContainer(0); | 
| Chris@216 | 612                 } else if (message.getArg(0).toString() == "layer") { | 
| Chris@216 | 613                     container = pane->getSelectedLayer(); | 
| Chris@216 | 614                 } | 
| Chris@2519 | 615             } else { | 
| Chris@2519 | 616                 SVCERR << "OSCHandler: Usage: /set <control> <value>" << endl | 
| Chris@2519 | 617                        << "               or  /set pane <control> <value>" << endl | 
| Chris@2519 | 618                        << "               or  /set layer <control> <value>" << endl; | 
| Chris@216 | 619             } | 
| Chris@216 | 620             if (container) { | 
| Chris@216 | 621                 QString nameString = message.getArg(1).toString(); | 
| Chris@216 | 622                 QString valueString = message.getArg(2).toString(); | 
| Chris@248 | 623                 Command *c = container->getSetPropertyCommand | 
| Chris@248 | 624                     (nameString, valueString); | 
| Chris@248 | 625                 if (c) CommandHistory::getInstance()->addCommand(c, true, true); | 
| Chris@216 | 626             } | 
| Chris@216 | 627         } | 
| Chris@216 | 628 | 
| Chris@216 | 629     } else if (message.getMethod() == "setcurrent") { | 
| Chris@216 | 630 | 
| Chris@216 | 631         int paneIndex = -1, layerIndex = -1; | 
| Chris@216 | 632         bool wantLayer = false; | 
| Chris@216 | 633 | 
| Chris@216 | 634         if (message.getArgCount() >= 1 && | 
| Chris@216 | 635             message.getArg(0).canConvert(QVariant::Int)) { | 
| Chris@216 | 636 | 
| Chris@216 | 637             paneIndex = message.getArg(0).toInt() - 1; | 
| Chris@216 | 638 | 
| Chris@216 | 639             if (message.getArgCount() >= 2 && | 
| Chris@216 | 640                 message.getArg(1).canConvert(QVariant::Int)) { | 
| Chris@216 | 641                 wantLayer = true; | 
| Chris@216 | 642                 layerIndex = message.getArg(1).toInt() - 1; | 
| Chris@216 | 643             } | 
| Chris@2519 | 644         } else { | 
| Chris@2519 | 645             SVCERR << "OSCHandler: Usage: /setcurrent <pane> [<layer>]" << endl; | 
| Chris@216 | 646         } | 
| Chris@216 | 647 | 
| Chris@216 | 648         if (paneIndex >= 0 && paneIndex < m_paneStack->getPaneCount()) { | 
| Chris@216 | 649             Pane *pane = m_paneStack->getPane(paneIndex); | 
| Chris@216 | 650             m_paneStack->setCurrentPane(pane); | 
| Chris@2441 | 651             SVDEBUG << "OSCHandler: Set current pane to index " | 
| Chris@2441 | 652                     << paneIndex << " (pane id " << pane->getId() | 
| Chris@2441 | 653                     << ")" << endl; | 
| Chris@216 | 654             if (layerIndex >= 0 && layerIndex < pane->getLayerCount()) { | 
| Chris@2437 | 655                 Layer *layer = pane->getFixedOrderLayer(layerIndex); | 
| Chris@216 | 656                 m_paneStack->setCurrentLayer(pane, layer); | 
| Chris@2441 | 657                 SVDEBUG << "OSCHandler: Set current layer to index " | 
| Chris@2441 | 658                         << layerIndex << " (layer \"" | 
| Chris@2441 | 659                         << layer->getLayerPresentationName() << "\")" << endl; | 
| Chris@216 | 660             } else if (wantLayer && layerIndex == -1) { | 
| Chris@2126 | 661                 m_paneStack->setCurrentLayer(pane, nullptr); | 
| Chris@2441 | 662             } else if (wantLayer) { | 
| Chris@2441 | 663                 SVCERR << "OSCHandler: Layer index " | 
| Chris@2441 | 664                        << layerIndex << " out of range for pane" << endl; | 
| Chris@2441 | 665             } | 
| Chris@216 | 666         } | 
| Chris@216 | 667 | 
| Chris@216 | 668     } else if (message.getMethod() == "delete") { | 
| Chris@216 | 669 | 
| Chris@216 | 670         if (message.getArgCount() == 1 && | 
| Chris@216 | 671             message.getArg(0).canConvert(QVariant::String)) { | 
| Chris@216 | 672 | 
| Chris@216 | 673             QString target = message.getArg(0).toString(); | 
| Chris@216 | 674 | 
| Chris@216 | 675             if (target == "pane") { | 
| Chris@216 | 676 | 
| Chris@2441 | 677                 SVDEBUG << "OSCHandler: Calling deleteCurrentPane" << endl; | 
| Chris@216 | 678                 deleteCurrentPane(); | 
| Chris@216 | 679 | 
| Chris@216 | 680             } else if (target == "layer") { | 
| Chris@216 | 681 | 
| Chris@2441 | 682                 SVDEBUG << "OSCHandler: Calling deleteCurrentLayer" << endl; | 
| Chris@216 | 683                 deleteCurrentLayer(); | 
| Chris@216 | 684 | 
| Chris@216 | 685             } else { | 
| Chris@216 | 686 | 
| Chris@2441 | 687                 SVCERR << "WARNING: OSCHandler: Unknown delete target \"" | 
| Chris@2441 | 688                        << target << "\"" << endl; | 
| Chris@216 | 689             } | 
| Chris@2519 | 690         } else { | 
| Chris@2519 | 691             SVCERR << "OSCHandler: Usage: /delete pane" << endl | 
| Chris@2519 | 692                    << "               or  /delete layer" << endl; | 
| Chris@216 | 693         } | 
| Chris@216 | 694 | 
| Chris@216 | 695     } else if (message.getMethod() == "zoom") { | 
| Chris@216 | 696 | 
| Chris@216 | 697         if (message.getArgCount() == 1) { | 
| Chris@216 | 698             if (message.getArg(0).canConvert(QVariant::String) && | 
| Chris@216 | 699                 message.getArg(0).toString() == "in") { | 
| Chris@216 | 700                 zoomIn(); | 
| Chris@216 | 701             } else if (message.getArg(0).canConvert(QVariant::String) && | 
| Chris@216 | 702                        message.getArg(0).toString() == "out") { | 
| Chris@216 | 703                 zoomOut(); | 
| Chris@216 | 704             } else if (message.getArg(0).canConvert(QVariant::String) && | 
| Chris@216 | 705                        message.getArg(0).toString() == "default") { | 
| Chris@216 | 706                 zoomDefault(); | 
| Chris@312 | 707             } else if (message.getArg(0).canConvert(QVariant::String) && | 
| Chris@312 | 708                        message.getArg(0).toString() == "fit") { | 
| Chris@312 | 709                 zoomToFit(); | 
| Chris@216 | 710             } else if (message.getArg(0).canConvert(QVariant::Double)) { | 
| Chris@216 | 711                 double level = message.getArg(0).toDouble(); | 
| Chris@216 | 712                 Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@2011 | 713                 ZoomLevel zoomLevel; | 
| Chris@2011 | 714                 if (level >= 0.66) { | 
| Chris@2011 | 715                     zoomLevel = ZoomLevel(ZoomLevel::FramesPerPixel, | 
| Chris@2011 | 716                                           int(round(level))); | 
| Chris@2011 | 717                 } else { | 
| Chris@2011 | 718                     zoomLevel = ZoomLevel(ZoomLevel::PixelsPerFrame, | 
| Chris@2011 | 719                                           int(round(1.0 / level))); | 
| Chris@2011 | 720                 } | 
| Chris@2011 | 721                 if (currentPane) { | 
| Chris@2441 | 722                     SVDEBUG << "OSCHandler: Setting zoom level to " | 
| Chris@2441 | 723                             << zoomLevel << endl; | 
| Chris@2011 | 724                     currentPane->setZoomLevel(zoomLevel); | 
| Chris@2441 | 725                 } else { | 
| Chris@2441 | 726                     SVCERR << "OSCHandler: No current pane, can't set zoom" | 
| Chris@2441 | 727                            << endl; | 
| Chris@2011 | 728                 } | 
| Chris@216 | 729             } | 
| Chris@2519 | 730         } else { | 
| Chris@2519 | 731             SVCERR << "OSCHandler: Usage: /zoom <level>" << endl | 
| Chris@2519 | 732                    << "               or  /zoom in" << endl | 
| Chris@2519 | 733                    << "               or  /zoom out" << endl | 
| Chris@2519 | 734                    << "               or  /zoom fit" << endl | 
| Chris@2519 | 735                    << "               or  /zoom default" << endl; | 
| Chris@216 | 736         } | 
| Chris@216 | 737 | 
| Chris@216 | 738     } else if (message.getMethod() == "zoomvertical") { | 
| Chris@216 | 739 | 
| Chris@216 | 740         Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@2126 | 741         Layer *layer = nullptr; | 
| Chris@216 | 742         if (pane && pane->getLayerCount() > 0) { | 
| Chris@216 | 743             layer = pane->getLayer(pane->getLayerCount() - 1); | 
| Chris@216 | 744         } | 
| Chris@216 | 745         int defaultStep = 0; | 
| Chris@216 | 746         int steps = 0; | 
| Chris@216 | 747         if (layer) { | 
| Chris@216 | 748             steps = layer->getVerticalZoomSteps(defaultStep); | 
| Chris@216 | 749             if (message.getArgCount() == 1 && steps > 0) { | 
| Chris@216 | 750                 if (message.getArg(0).canConvert(QVariant::String) && | 
| Chris@216 | 751                     message.getArg(0).toString() == "in") { | 
| Chris@216 | 752                     int step = layer->getCurrentVerticalZoomStep() + 1; | 
| Chris@216 | 753                     if (step < steps) layer->setVerticalZoomStep(step); | 
| Chris@216 | 754                 } else if (message.getArg(0).canConvert(QVariant::String) && | 
| Chris@216 | 755                            message.getArg(0).toString() == "out") { | 
| Chris@216 | 756                     int step = layer->getCurrentVerticalZoomStep() - 1; | 
| Chris@216 | 757                     if (step >= 0) layer->setVerticalZoomStep(step); | 
| Chris@216 | 758                 } else if (message.getArg(0).canConvert(QVariant::String) && | 
| Chris@216 | 759                            message.getArg(0).toString() == "default") { | 
| Chris@216 | 760                     layer->setVerticalZoomStep(defaultStep); | 
| Chris@216 | 761                 } | 
| Chris@216 | 762             } else if (message.getArgCount() == 2) { | 
| Chris@216 | 763                 if (message.getArg(0).canConvert(QVariant::Double) && | 
| Chris@216 | 764                     message.getArg(1).canConvert(QVariant::Double)) { | 
| Chris@216 | 765                     double min = message.getArg(0).toDouble(); | 
| Chris@216 | 766                     double max = message.getArg(1).toDouble(); | 
| Chris@216 | 767                     layer->setDisplayExtents(min, max); | 
| Chris@216 | 768                 } | 
| Chris@216 | 769             } | 
| Chris@216 | 770         } | 
| Chris@216 | 771 | 
| Chris@216 | 772     } else if (message.getMethod() == "quit") { | 
| Chris@2440 | 773 | 
| Chris@2440 | 774         SVDEBUG << "OSCHandler: Exiting abruptly" << endl; | 
| Chris@2529 | 775 | 
| Chris@2529 | 776         // discard any more pending OSC messages | 
| Chris@2529 | 777         if (m_oscQueue) { | 
| Chris@2529 | 778             while (!m_oscQueue->isEmpty()) { | 
| Chris@2529 | 779                 (void)m_oscQueue->readMessage(); | 
| Chris@2529 | 780             } | 
| Chris@2529 | 781         } | 
| Chris@2529 | 782 | 
| Chris@2440 | 783         m_documentModified = false; // so we don't ask to save | 
| Chris@216 | 784         close(); | 
| Chris@216 | 785 | 
| Chris@216 | 786     } else if (message.getMethod() == "resize") { | 
| Chris@216 | 787 | 
| Chris@216 | 788         if (message.getArgCount() == 2) { | 
| Chris@216 | 789 | 
| Chris@216 | 790             int width = 0, height = 0; | 
| Chris@216 | 791 | 
| Chris@216 | 792             if (message.getArg(1).canConvert(QVariant::Int)) { | 
| Chris@216 | 793 | 
| Chris@216 | 794                 height = message.getArg(1).toInt(); | 
| Chris@216 | 795 | 
| Chris@216 | 796                 if (message.getArg(0).canConvert(QVariant::String) && | 
| Chris@216 | 797                     message.getArg(0).toString() == "pane") { | 
| Chris@216 | 798 | 
| Chris@216 | 799                     Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@216 | 800                     if (pane) pane->resize(pane->width(), height); | 
| Chris@216 | 801 | 
| Chris@216 | 802                 } else if (message.getArg(0).canConvert(QVariant::Int)) { | 
| Chris@216 | 803 | 
| Chris@216 | 804                     width = message.getArg(0).toInt(); | 
| Chris@216 | 805                     resize(width, height); | 
| Chris@216 | 806                 } | 
| Chris@216 | 807             } | 
| Chris@216 | 808         } | 
| Chris@216 | 809 | 
| Chris@216 | 810     } else if (message.getMethod() == "transform") { | 
| Chris@216 | 811 | 
| Chris@2441 | 812         if (message.getArgCount() == 1 && | 
| Chris@216 | 813             message.getArg(0).canConvert(QVariant::String)) { | 
| Chris@216 | 814 | 
| Chris@2441 | 815             Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@2441 | 816 | 
| Chris@2441 | 817             if (getMainModel() && pane) { | 
| Chris@216 | 818 | 
| Chris@2441 | 819                 TransformId transformId = message.getArg(0).toString(); | 
| Chris@2441 | 820 | 
| Chris@2441 | 821                 Transform transform = TransformFactory::getInstance()-> | 
| Chris@2441 | 822                     getDefaultTransformFor(transformId); | 
| Chris@2441 | 823 | 
| Chris@2441 | 824                 SVDEBUG << "OSCHandler: Running transform on main model:" | 
| Chris@2441 | 825                         << transform.toXmlString() << endl; | 
| Chris@1770 | 826 | 
| Chris@2441 | 827                 Layer *newLayer = m_document->createDerivedLayer | 
| Chris@2441 | 828                     (transform, getMainModelId()); | 
| Chris@2441 | 829 | 
| Chris@2441 | 830                 if (newLayer) { | 
| Chris@2441 | 831                     m_document->addLayerToView(pane, newLayer); | 
| Chris@2441 | 832                     m_recentTransforms.add(transformId); | 
| Chris@2441 | 833                     m_paneStack->setCurrentLayer(pane, newLayer); | 
| Chris@2441 | 834                 } else { | 
| Chris@2441 | 835                     SVCERR << "OSCHandler: Transform failed to run" << endl; | 
| Chris@2441 | 836                 } | 
| Chris@2441 | 837             } else { | 
| Chris@2441 | 838                 SVCERR << "OSCHandler: Lack main model or pane, " | 
| Chris@2441 | 839                        << "can't run transform" << endl; | 
| Chris@216 | 840             } | 
| Chris@2441 | 841         } | 
| Chris@216 | 842 | 
| Chris@216 | 843     } else { | 
| Chris@2441 | 844         SVCERR << "WARNING: OSCHandler: Unknown or unsupported " | 
| Chris@665 | 845                   << "method \"" << message.getMethod() | 
| Chris@665 | 846                   << "\"" << endl; | 
| Chris@216 | 847     } | 
| Chris@2441 | 848 | 
| Chris@2441 | 849     SVDEBUG << "OSCHandler at " << NOW << ": finished message: " | 
| Chris@2441 | 850             << message.toString() << " in " << timer.elapsed() << "ms" << endl; | 
| Chris@216 | 851 } |