Chris@224: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
Chris@224: 
Chris@224: /*
Chris@224:     Sonic Visualiser
Chris@224:     An audio file viewer and annotation editor.
Chris@224:     Centre for Digital Music, Queen Mary, University of London.
Chris@224:     This file copyright 2006-2007 Chris Cannam and QMUL.
Chris@224:     
Chris@224:     This program is free software; you can redistribute it and/or
Chris@224:     modify it under the terms of the GNU General Public License as
Chris@224:     published by the Free Software Foundation; either version 2 of the
Chris@224:     License, or (at your option) any later version.  See the file
Chris@224:     COPYING included with this distribution for more information.
Chris@224: */
Chris@216: 
Chris@216: #include "MainWindow.h"
Chris@216: #include "data/osc/OSCQueue.h"
Chris@216: 
Chris@216: #include "layer/WaveformLayer.h"
Chris@216: #include "view/ViewManager.h"
Chris@216: #include "view/Pane.h"
Chris@216: #include "view/PaneStack.h"
Chris@216: #include "data/model/WaveFileModel.h"
Chris@248: #include "widgets/CommandHistory.h"
Chris@1035: #include "audio/AudioCallbackPlaySource.h"
Chris@216: #include "framework/Document.h"
Chris@216: #include "data/fileio/WavFileWriter.h"
Chris@249: #include "transform/TransformFactory.h"
Chris@1386: #include "widgets/LevelPanWidget.h"
Chris@1431: #include "widgets/LevelPanToolButton.h"
Chris@216: #include "widgets/AudioDial.h"
Chris@216: 
Chris@1035: #include <bqaudioio/SystemPlaybackTarget.h>
Chris@1035: 
Chris@216: #include <QFileInfo>
Chris@216: 
Chris@216: void
Chris@216: MainWindow::handleOSCMessage(const OSCMessage &message)
Chris@216: {
Chris@438:     SVDEBUG << "MainWindow::handleOSCMessage: thread id = " 
Chris@433:               << QThread::currentThreadId() << endl;
Chris@216: 
Chris@216:     // This large function should really be abstracted out.
Chris@216: 
Chris@216:     if (message.getMethod() == "open") {
Chris@216: 
Chris@216:         if (message.getArgCount() == 1 &&
Chris@216:             message.getArg(0).canConvert(QVariant::String)) {
Chris@216:             QString path = message.getArg(0).toString();
Chris@216:             if (open(path, ReplaceMainModel) != FileOpenSucceeded) {
Chris@665:                 cerr << "MainWindow::handleOSCMessage: File open failed for path \""
Chris@665:                           << path << "\"" << endl;
Chris@216:             }
Chris@216:             //!!! we really need to spin here and not return until the
Chris@216:             // file has been completely decoded...
Chris@216:         }
Chris@216: 
Chris@216:     } else if (message.getMethod() == "openadditional") {
Chris@216: 
Chris@216:         if (message.getArgCount() == 1 &&
Chris@216:             message.getArg(0).canConvert(QVariant::String)) {
Chris@216:             QString path = message.getArg(0).toString();
Chris@216:             if (open(path, CreateAdditionalModel) != FileOpenSucceeded) {
Chris@665:                 cerr << "MainWindow::handleOSCMessage: File open failed for path \""
Chris@665:                           << path << "\"" << endl;
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@216:     } else if (message.getMethod() == "recent" ||
Chris@216:                message.getMethod() == "last") {
Chris@216: 
Chris@216:         int n = 0;
Chris@216:         if (message.getMethod() == "recent" &&
Chris@216:             message.getArgCount() == 1 &&
Chris@216:             message.getArg(0).canConvert(QVariant::Int)) {
Chris@216:             n = message.getArg(0).toInt() - 1;
Chris@216:         }
Chris@216:         std::vector<QString> recent = m_recentFiles.getRecent();
Chris@216:         if (n >= 0 && n < int(recent.size())) {
Chris@216:             if (open(recent[n], ReplaceMainModel) != FileOpenSucceeded) {
Chris@665:                 cerr << "MainWindow::handleOSCMessage: File open failed for path \""
Chris@665:                           << recent[n] << "\"" << endl;
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@216:     } else if (message.getMethod() == "save") {
Chris@216: 
Chris@216:         QString path;
Chris@216:         if (message.getArgCount() == 1 &&
Chris@216:             message.getArg(0).canConvert(QVariant::String)) {
Chris@216:             path = message.getArg(0).toString();
Chris@216:             if (QFileInfo(path).exists()) {
Chris@438:                 SVDEBUG << "MainWindow::handleOSCMessage: Refusing to overwrite existing file in save" << endl;
Chris@216:             } else {
Chris@216:                 saveSessionFile(path);
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@216:     } else if (message.getMethod() == "export") {
Chris@216: 
Chris@216:         QString path;
Chris@216:         if (getMainModel()) {
Chris@216:             if (message.getArgCount() == 1 &&
Chris@216:                 message.getArg(0).canConvert(QVariant::String)) {
Chris@216:                 path = message.getArg(0).toString();
Chris@216:                 if (QFileInfo(path).exists()) {
Chris@438:                     SVDEBUG << "MainWindow::handleOSCMessage: Refusing to overwrite existing file in export" << endl;
Chris@216:                 } else {
Chris@216:                     WavFileWriter writer(path,
Chris@216:                                          getMainModel()->getSampleRate(),
Chris@428:                                          getMainModel()->getChannelCount(),
Chris@428:                                          WavFileWriter::WriteToTemporary);
Chris@216:                     MultiSelection ms = m_viewManager->getSelection();
Chris@216:                     if (!ms.getSelections().empty()) {
Chris@216:                         writer.writeModel(getMainModel(), &ms);
Chris@216:                     } else {
Chris@216:                         writer.writeModel(getMainModel());
Chris@216:                     }
Chris@216:                 }
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@216:     } else if (message.getMethod() == "jump" ||
Chris@216:                message.getMethod() == "play") {
Chris@216: 
Chris@216:         if (getMainModel()) {
Chris@216: 
Chris@922:             sv_frame_t frame = m_viewManager->getPlaybackFrame();
Chris@216:             bool selection = false;
Chris@216:             bool play = (message.getMethod() == "play");
Chris@216: 
Chris@216:             if (message.getArgCount() == 1) {
Chris@216: 
Chris@216:                 if (message.getArg(0).canConvert(QVariant::String) &&
Chris@216:                     message.getArg(0).toString() == "selection") {
Chris@216: 
Chris@216:                     selection = true;
Chris@216: 
Chris@216:                 } else if (message.getArg(0).canConvert(QVariant::String) &&
Chris@216:                            message.getArg(0).toString() == "end") {
Chris@216: 
Chris@216:                     frame = getMainModel()->getEndFrame();
Chris@216: 
Chris@216:                 } else if (message.getArg(0).canConvert(QVariant::Double)) {
Chris@216: 
Chris@216:                     double time = message.getArg(0).toDouble();
Chris@216:                     if (time < 0.0) time = 0.0;
Chris@216: 
Chris@216:                     frame = lrint(time * getMainModel()->getSampleRate());
Chris@216:                 }
Chris@216:             }
Chris@216: 
Chris@216:             if (frame > getMainModel()->getEndFrame()) {
Chris@216:                 frame = getMainModel()->getEndFrame();
Chris@216:             }
Chris@216: 
Chris@216:             if (play) {
Chris@216:                 m_viewManager->setPlaySelectionMode(selection);
Chris@216:             } 
Chris@216: 
Chris@216:             if (selection) {
Chris@216:                 MultiSelection::SelectionList sl = m_viewManager->getSelections();
Chris@216:                 if (!sl.empty()) {
Chris@216:                     frame = sl.begin()->getStartFrame();
Chris@216:                 }
Chris@216:             }
Chris@216: 
Chris@216:             m_viewManager->setPlaybackFrame(frame);
Chris@216: 
Chris@216:             if (play && !m_playSource->isPlaying()) {
Chris@216:                 m_playSource->play(frame);
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@313:     } else if (message.getMethod() == "ffwd") {
Chris@313: 
Chris@313:         if (message.getArgCount() == 1) {
Chris@313: 
Chris@313:             if (message.getArg(0).canConvert(QVariant::String) &&
Chris@313:                 message.getArg(0).toString() == "similar") {
Chris@313: 
Chris@313:                 ffwdSimilar();
Chris@313:             }
Chris@313:         } else {
Chris@313: 
Chris@313:             ffwd();
Chris@313:         }
Chris@313: 
Chris@313:     } else if (message.getMethod() == "rewind") {
Chris@313: 
Chris@313:         if (message.getArgCount() == 1) {
Chris@313: 
Chris@313:             if (message.getArg(0).canConvert(QVariant::String) &&
Chris@313:                 message.getArg(0).toString() == "similar") {
Chris@313: 
Chris@313:                 rewindSimilar();
Chris@313:             }
Chris@313:         } else {
Chris@313: 
Chris@313:             rewind();
Chris@313:         }
Chris@313: 
Chris@216:     } else if (message.getMethod() == "stop") {
Chris@216:             
Chris@216:         if (m_playSource->isPlaying()) m_playSource->stop();
Chris@216: 
Chris@216:     } else if (message.getMethod() == "loop") {
Chris@216: 
Chris@216:         if (message.getArgCount() == 1 &&
Chris@216:             message.getArg(0).canConvert(QVariant::String)) {
Chris@216: 
Chris@216:             QString str = message.getArg(0).toString();
Chris@216:             if (str == "on") {
Chris@216:                 m_viewManager->setPlayLoopMode(true);
Chris@216:             } else if (str == "off") {
Chris@216:                 m_viewManager->setPlayLoopMode(false);
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@216:     } else if (message.getMethod() == "solo") {
Chris@216: 
Chris@216:         if (message.getArgCount() == 1 &&
Chris@216:             message.getArg(0).canConvert(QVariant::String)) {
Chris@216: 
Chris@216:             QString str = message.getArg(0).toString();
Chris@216:             if (str == "on") {
Chris@216:                 m_viewManager->setPlaySoloMode(true);
Chris@216:             } else if (str == "off") {
Chris@216:                 m_viewManager->setPlaySoloMode(false);
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@216:     } else if (message.getMethod() == "select" ||
Chris@216:                message.getMethod() == "addselect") {
Chris@216: 
Chris@216:         if (getMainModel()) {
Chris@216: 
Chris@920:             sv_frame_t f0 = getMainModel()->getStartFrame();
Chris@920:             sv_frame_t f1 = getMainModel()->getEndFrame();
Chris@216: 
Chris@216:             bool done = false;
Chris@216: 
Chris@216:             if (message.getArgCount() == 2 &&
Chris@216:                 message.getArg(0).canConvert(QVariant::Double) &&
Chris@216:                 message.getArg(1).canConvert(QVariant::Double)) {
Chris@216:                 
Chris@216:                 double t0 = message.getArg(0).toDouble();
Chris@216:                 double t1 = message.getArg(1).toDouble();
Chris@216:                 if (t1 < t0) { double temp = t0; t0 = t1; t1 = temp; }
Chris@216:                 if (t0 < 0.0) t0 = 0.0;
Chris@216:                 if (t1 < 0.0) t1 = 0.0;
Chris@216: 
Chris@216:                 f0 = lrint(t0 * getMainModel()->getSampleRate());
Chris@216:                 f1 = lrint(t1 * getMainModel()->getSampleRate());
Chris@216:                 
Chris@216:                 Pane *pane = m_paneStack->getCurrentPane();
Chris@216:                 Layer *layer = 0;
Chris@216:                 if (pane) layer = pane->getSelectedLayer();
Chris@216:                 if (layer) {
Chris@730:                     int resolution;
Chris@216:                     layer->snapToFeatureFrame(pane, f0, resolution,
Chris@216:                                               Layer::SnapLeft);
Chris@216:                     layer->snapToFeatureFrame(pane, f1, resolution,
Chris@216:                                               Layer::SnapRight);
Chris@216:                 }
Chris@216: 
Chris@216:             } else if (message.getArgCount() == 1 &&
Chris@216:                        message.getArg(0).canConvert(QVariant::String)) {
Chris@216: 
Chris@216:                 QString str = message.getArg(0).toString();
Chris@216:                 if (str == "none") {
Chris@216:                     m_viewManager->clearSelections();
Chris@216:                     done = true;
Chris@216:                 }
Chris@216:             }
Chris@216: 
Chris@216:             if (!done) {
Chris@216:                 if (message.getMethod() == "select") {
Chris@216:                     m_viewManager->setSelection(Selection(f0, f1));
Chris@216:                 } else {
Chris@216:                     m_viewManager->addSelection(Selection(f0, f1));
Chris@216:                 }
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@216:     } else if (message.getMethod() == "add") {
Chris@216: 
Chris@216:         if (getMainModel()) {
Chris@216: 
Chris@216:             if (message.getArgCount() >= 1 &&
Chris@216:                 message.getArg(0).canConvert(QVariant::String)) {
Chris@216: 
Chris@216:                 int channel = -1;
Chris@216:                 if (message.getArgCount() == 2 &&
Chris@216:                     message.getArg(0).canConvert(QVariant::Int)) {
Chris@216:                     channel = message.getArg(0).toInt();
Chris@216:                     if (channel < -1 ||
Chris@216:                         channel > int(getMainModel()->getChannelCount())) {
Chris@665:                         cerr << "WARNING: MainWindow::handleOSCMessage: channel "
Chris@665:                                   << channel << " out of range" << endl;
Chris@216:                         channel = -1;
Chris@216:                     }
Chris@216:                 }
Chris@216: 
Chris@216:                 QString str = message.getArg(0).toString();
Chris@216:                 
Chris@216:                 LayerFactory::LayerType type =
Chris@216:                     LayerFactory::getInstance()->getLayerTypeForName(str);
Chris@216: 
Chris@216:                 if (type == LayerFactory::UnknownLayer) {
Chris@665:                     cerr << "WARNING: MainWindow::handleOSCMessage: unknown layer "
Chris@665:                               << "type " << str << endl;
Chris@216:                 } else {
Chris@216: 
Chris@232:                     LayerConfiguration configuration(type,
Chris@232:                                                      getMainModel(),
Chris@232:                                                      channel);
Chris@216:                     
Chris@216:                     addPane(configuration,
Chris@216:                             tr("Add %1 Pane")
Chris@216:                             .arg(LayerFactory::getInstance()->
Chris@216:                                  getLayerPresentationName(type)));
Chris@216:                 }
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@216:     } else if (message.getMethod() == "undo") {
Chris@216: 
Chris@216:         CommandHistory::getInstance()->undo();
Chris@216: 
Chris@216:     } else if (message.getMethod() == "redo") {
Chris@216: 
Chris@216:         CommandHistory::getInstance()->redo();
Chris@216: 
Chris@216:     } else if (message.getMethod() == "set") {
Chris@216: 
Chris@216:         if (message.getArgCount() == 2 &&
Chris@216:             message.getArg(0).canConvert(QVariant::String) &&
Chris@216:             message.getArg(1).canConvert(QVariant::Double)) {
Chris@216: 
Chris@216:             QString property = message.getArg(0).toString();
Chris@216:             float value = (float)message.getArg(1).toDouble();
Chris@216: 
Chris@216:             if (property == "gain") {
Chris@216:                 if (value < 0.0) value = 0.0;
Chris@1386:                 m_mainLevelPan->setLevel(value);
Chris@216:                 if (m_playTarget) m_playTarget->setOutputGain(value);
Chris@216:             } else if (property == "speedup") {
Chris@216:                 m_playSpeed->setMappedValue(value);
Chris@216:             } else if (property == "overlays") {
Chris@216:                 if (value < 0.5) {
Chris@216:                     m_viewManager->setOverlayMode(ViewManager::NoOverlays);
Chris@216:                 } else if (value < 1.5) {
Chris@701:                     m_viewManager->setOverlayMode(ViewManager::StandardOverlays);
Chris@216:                 } else {
Chris@216:                     m_viewManager->setOverlayMode(ViewManager::AllOverlays);
Chris@216:                 }                    
Chris@216:             } else if (property == "zoomwheels") {
Chris@216:                 m_viewManager->setZoomWheelsEnabled(value > 0.5);
Chris@216:             } else if (property == "propertyboxes") {
Chris@216:                 bool toggle = ((value < 0.5) !=
Chris@216:                                (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks));
Chris@216:                 if (toggle) togglePropertyBoxes();
Chris@216:             }
Chris@216:                 
Chris@216:         } else {
Chris@216:             PropertyContainer *container = 0;
Chris@216:             Pane *pane = m_paneStack->getCurrentPane();
Chris@216:             if (pane &&
Chris@216:                 message.getArgCount() == 3 &&
Chris@216:                 message.getArg(0).canConvert(QVariant::String) &&
Chris@216:                 message.getArg(1).canConvert(QVariant::String) &&
Chris@216:                 message.getArg(2).canConvert(QVariant::String)) {
Chris@216:                 if (message.getArg(0).toString() == "pane") {
Chris@216:                     container = pane->getPropertyContainer(0);
Chris@216:                 } else if (message.getArg(0).toString() == "layer") {
Chris@216:                     container = pane->getSelectedLayer();
Chris@216:                 }
Chris@216:             }
Chris@216:             if (container) {
Chris@216:                 QString nameString = message.getArg(1).toString();
Chris@216:                 QString valueString = message.getArg(2).toString();
Chris@248:                 Command *c = container->getSetPropertyCommand
Chris@248:                     (nameString, valueString);
Chris@248:                 if (c) CommandHistory::getInstance()->addCommand(c, true, true);
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@216:     } else if (message.getMethod() == "setcurrent") {
Chris@216: 
Chris@216:         int paneIndex = -1, layerIndex = -1;
Chris@216:         bool wantLayer = false;
Chris@216: 
Chris@216:         if (message.getArgCount() >= 1 &&
Chris@216:             message.getArg(0).canConvert(QVariant::Int)) {
Chris@216: 
Chris@216:             paneIndex = message.getArg(0).toInt() - 1;
Chris@216: 
Chris@216:             if (message.getArgCount() >= 2 &&
Chris@216:                 message.getArg(1).canConvert(QVariant::Int)) {
Chris@216:                 wantLayer = true;
Chris@216:                 layerIndex = message.getArg(1).toInt() - 1;
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@216:         if (paneIndex >= 0 && paneIndex < m_paneStack->getPaneCount()) {
Chris@216:             Pane *pane = m_paneStack->getPane(paneIndex);
Chris@216:             m_paneStack->setCurrentPane(pane);
Chris@216:             if (layerIndex >= 0 && layerIndex < pane->getLayerCount()) {
Chris@216:                 Layer *layer = pane->getLayer(layerIndex);
Chris@216:                 m_paneStack->setCurrentLayer(pane, layer);
Chris@216:             } else if (wantLayer && layerIndex == -1) {
Chris@216:                 m_paneStack->setCurrentLayer(pane, 0);
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@216:     } else if (message.getMethod() == "delete") {
Chris@216: 
Chris@216:         if (message.getArgCount() == 1 &&
Chris@216:             message.getArg(0).canConvert(QVariant::String)) {
Chris@216:             
Chris@216:             QString target = message.getArg(0).toString();
Chris@216: 
Chris@216:             if (target == "pane") {
Chris@216: 
Chris@216:                 deleteCurrentPane();
Chris@216: 
Chris@216:             } else if (target == "layer") {
Chris@216: 
Chris@216:                 deleteCurrentLayer();
Chris@216: 
Chris@216:             } else {
Chris@216:                 
Chris@665:                 cerr << "WARNING: MainWindow::handleOSCMessage: Unknown delete target " << target << endl;
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@216:     } else if (message.getMethod() == "zoom") {
Chris@216: 
Chris@216:         if (message.getArgCount() == 1) {
Chris@216:             if (message.getArg(0).canConvert(QVariant::String) &&
Chris@216:                 message.getArg(0).toString() == "in") {
Chris@216:                 zoomIn();
Chris@216:             } else if (message.getArg(0).canConvert(QVariant::String) &&
Chris@216:                        message.getArg(0).toString() == "out") {
Chris@216:                 zoomOut();
Chris@216:             } else if (message.getArg(0).canConvert(QVariant::String) &&
Chris@216:                        message.getArg(0).toString() == "default") {
Chris@216:                 zoomDefault();
Chris@312:             } else if (message.getArg(0).canConvert(QVariant::String) &&
Chris@312:                        message.getArg(0).toString() == "fit") {
Chris@312:                 zoomToFit();
Chris@216:             } else if (message.getArg(0).canConvert(QVariant::Double)) {
Chris@216:                 double level = message.getArg(0).toDouble();
Chris@216:                 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@216:                 if (level < 1.0) level = 1.0;
Chris@922:                 if (currentPane) currentPane->setZoomLevel(int(lrint(level)));
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@216:     } else if (message.getMethod() == "zoomvertical") {
Chris@216: 
Chris@216:         Pane *pane = m_paneStack->getCurrentPane();
Chris@216:         Layer *layer = 0;
Chris@216:         if (pane && pane->getLayerCount() > 0) {
Chris@216:             layer = pane->getLayer(pane->getLayerCount() - 1);
Chris@216:         }
Chris@216:         int defaultStep = 0;
Chris@216:         int steps = 0;
Chris@216:         if (layer) {
Chris@216:             steps = layer->getVerticalZoomSteps(defaultStep);
Chris@216:             if (message.getArgCount() == 1 && steps > 0) {
Chris@216:                 if (message.getArg(0).canConvert(QVariant::String) &&
Chris@216:                     message.getArg(0).toString() == "in") {
Chris@216:                     int step = layer->getCurrentVerticalZoomStep() + 1;
Chris@216:                     if (step < steps) layer->setVerticalZoomStep(step);
Chris@216:                 } else if (message.getArg(0).canConvert(QVariant::String) &&
Chris@216:                            message.getArg(0).toString() == "out") {
Chris@216:                     int step = layer->getCurrentVerticalZoomStep() - 1;
Chris@216:                     if (step >= 0) layer->setVerticalZoomStep(step);
Chris@216:                 } else if (message.getArg(0).canConvert(QVariant::String) &&
Chris@216:                            message.getArg(0).toString() == "default") {
Chris@216:                     layer->setVerticalZoomStep(defaultStep);
Chris@216:                 }
Chris@216:             } else if (message.getArgCount() == 2) {
Chris@216:                 if (message.getArg(0).canConvert(QVariant::Double) &&
Chris@216:                     message.getArg(1).canConvert(QVariant::Double)) {
Chris@216:                     double min = message.getArg(0).toDouble();
Chris@216:                     double max = message.getArg(1).toDouble();
Chris@216:                     layer->setDisplayExtents(min, max);
Chris@216:                 }
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@216:     } else if (message.getMethod() == "quit") {
Chris@216:         
Chris@216:         m_abandoning = true;
Chris@216:         close();
Chris@216: 
Chris@216:     } else if (message.getMethod() == "resize") {
Chris@216:         
Chris@216:         if (message.getArgCount() == 2) {
Chris@216: 
Chris@216:             int width = 0, height = 0;
Chris@216: 
Chris@216:             if (message.getArg(1).canConvert(QVariant::Int)) {
Chris@216: 
Chris@216:                 height = message.getArg(1).toInt();
Chris@216: 
Chris@216:                 if (message.getArg(0).canConvert(QVariant::String) &&
Chris@216:                     message.getArg(0).toString() == "pane") {
Chris@216: 
Chris@216:                     Pane *pane = m_paneStack->getCurrentPane();
Chris@216:                     if (pane) pane->resize(pane->width(), height);
Chris@216: 
Chris@216:                 } else if (message.getArg(0).canConvert(QVariant::Int)) {
Chris@216: 
Chris@216:                     width = message.getArg(0).toInt();
Chris@216:                     resize(width, height);
Chris@216:                 }
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@216:     } else if (message.getMethod() == "transform") {
Chris@216: 
Chris@216:         Pane *pane = m_paneStack->getCurrentPane();
Chris@216: 
Chris@216:         if (getMainModel() &&
Chris@216:             pane &&
Chris@216:             message.getArgCount() == 1 &&
Chris@216:             message.getArg(0).canConvert(QVariant::String)) {
Chris@216: 
Chris@224:             TransformId transformId = message.getArg(0).toString();
Chris@216: 
Chris@224: 	    Transform transform = TransformFactory::getInstance()->
Chris@224:                 getDefaultTransformFor(transformId);
Chris@224: 	    
Chris@216:             Layer *newLayer = m_document->createDerivedLayer
Chris@224:                 (transform, getMainModel());
Chris@216: 
Chris@216:             if (newLayer) {
Chris@216:                 m_document->addLayerToView(pane, newLayer);
Chris@224:                 m_recentTransforms.add(transformId);
Chris@216:                 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@216:             }
Chris@216:         }
Chris@216: 
Chris@216:     } else {
Chris@665:         cerr << "WARNING: MainWindow::handleOSCMessage: Unknown or unsupported "
Chris@665:                   << "method \"" << message.getMethod()
Chris@665:                   << "\"" << endl;
Chris@216:     }
Chris@216:             
Chris@216: }