Mercurial > hg > sonic-visualiser
comparison main/MainWindow.cpp @ 216:1fa0d271fd2c
* Pull out MainWindow::handleOSCMessage() into a separate file
author | Chris Cannam |
---|---|
date | Thu, 22 Nov 2007 14:13:20 +0000 |
parents | 11ca12902c6a |
children | 69f83e36b8e5 |
comparison
equal
deleted
inserted
replaced
215:79ea249689d9 | 216:1fa0d271fd2c |
---|---|
14 */ | 14 */ |
15 | 15 |
16 #include "../version.h" | 16 #include "../version.h" |
17 | 17 |
18 #include "MainWindow.h" | 18 #include "MainWindow.h" |
19 #include "framework/Document.h" | |
20 #include "PreferencesDialog.h" | 19 #include "PreferencesDialog.h" |
21 | 20 |
22 #include "view/Pane.h" | 21 #include "view/Pane.h" |
23 #include "view/PaneStack.h" | 22 #include "view/PaneStack.h" |
24 #include "data/model/WaveFileModel.h" | 23 #include "data/model/WaveFileModel.h" |
25 #include "data/model/SparseOneDimensionalModel.h" | 24 #include "data/model/SparseOneDimensionalModel.h" |
26 #include "data/model/NoteModel.h" | 25 #include "data/model/NoteModel.h" |
27 #include "data/model/Labeller.h" | 26 #include "data/model/Labeller.h" |
27 #include "framework/Document.h" | |
28 #include "view/ViewManager.h" | 28 #include "view/ViewManager.h" |
29 #include "base/Preferences.h" | 29 #include "base/Preferences.h" |
30 #include "layer/WaveformLayer.h" | 30 #include "layer/WaveformLayer.h" |
31 #include "layer/TimeRulerLayer.h" | 31 #include "layer/TimeRulerLayer.h" |
32 #include "layer/TimeInstantLayer.h" | 32 #include "layer/TimeInstantLayer.h" |
67 #include "base/CommandHistory.h" | 67 #include "base/CommandHistory.h" |
68 #include "base/Profiler.h" | 68 #include "base/Profiler.h" |
69 #include "base/Clipboard.h" | 69 #include "base/Clipboard.h" |
70 #include "base/UnitDatabase.h" | 70 #include "base/UnitDatabase.h" |
71 #include "base/ColourDatabase.h" | 71 #include "base/ColourDatabase.h" |
72 #include "data/osc/OSCQueue.h" | |
73 | 72 |
74 // For version information | 73 // For version information |
75 #include "vamp/vamp.h" | 74 #include "vamp/vamp.h" |
76 #include "vamp-sdk/PluginBase.h" | 75 #include "vamp-sdk/PluginBase.h" |
77 #include "plugin/api/ladspa.h" | 76 #include "plugin/api/ladspa.h" |
1437 ti->second->setShortcut(tr("Ctrl+T")); | 1436 ti->second->setShortcut(tr("Ctrl+T")); |
1438 m_keyReference->registerShortcut | 1437 m_keyReference->registerShortcut |
1439 (tr("Repeat Transform"), | 1438 (tr("Repeat Transform"), |
1440 ti->second->shortcut(), | 1439 ti->second->shortcut(), |
1441 tr("Re-select the most recently run transform")); | 1440 tr("Re-select the most recently run transform")); |
1441 } else { | |
1442 ti->second->setShortcut(QString("")); | |
1442 } | 1443 } |
1443 m_recentTransformsMenu->addAction(ti->second); | 1444 m_recentTransformsMenu->addAction(ti->second); |
1444 } | 1445 } |
1445 } | 1446 } |
1446 | 1447 |
3242 LayerTreeModel *tree = new LayerTreeModel(m_paneStack); | 3243 LayerTreeModel *tree = new LayerTreeModel(m_paneStack); |
3243 m_layerTreeView->resize(500, 300); //!!! | 3244 m_layerTreeView->resize(500, 300); //!!! |
3244 m_layerTreeView->setModel(tree); | 3245 m_layerTreeView->setModel(tree); |
3245 m_layerTreeView->expandAll(); | 3246 m_layerTreeView->expandAll(); |
3246 m_layerTreeView->show(); | 3247 m_layerTreeView->show(); |
3247 } | |
3248 | |
3249 void | |
3250 MainWindow::handleOSCMessage(const OSCMessage &message) | |
3251 { | |
3252 std::cerr << "MainWindow::handleOSCMessage: thread id = " | |
3253 << QThread::currentThreadId() << std::endl; | |
3254 | |
3255 // This large function should really be abstracted out. | |
3256 | |
3257 if (message.getMethod() == "open") { | |
3258 | |
3259 if (message.getArgCount() == 1 && | |
3260 message.getArg(0).canConvert(QVariant::String)) { | |
3261 QString path = message.getArg(0).toString(); | |
3262 if (open(path, ReplaceMainModel) != FileOpenSucceeded) { | |
3263 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \"" | |
3264 << path.toStdString() << "\"" << std::endl; | |
3265 } | |
3266 //!!! we really need to spin here and not return until the | |
3267 // file has been completely decoded... | |
3268 } | |
3269 | |
3270 } else if (message.getMethod() == "openadditional") { | |
3271 | |
3272 if (message.getArgCount() == 1 && | |
3273 message.getArg(0).canConvert(QVariant::String)) { | |
3274 QString path = message.getArg(0).toString(); | |
3275 if (open(path, CreateAdditionalModel) != FileOpenSucceeded) { | |
3276 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \"" | |
3277 << path.toStdString() << "\"" << std::endl; | |
3278 } | |
3279 } | |
3280 | |
3281 } else if (message.getMethod() == "recent" || | |
3282 message.getMethod() == "last") { | |
3283 | |
3284 int n = 0; | |
3285 if (message.getMethod() == "recent" && | |
3286 message.getArgCount() == 1 && | |
3287 message.getArg(0).canConvert(QVariant::Int)) { | |
3288 n = message.getArg(0).toInt() - 1; | |
3289 } | |
3290 std::vector<QString> recent = m_recentFiles.getRecent(); | |
3291 if (n >= 0 && n < int(recent.size())) { | |
3292 if (open(recent[n], ReplaceMainModel) != FileOpenSucceeded) { | |
3293 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \"" | |
3294 << recent[n].toStdString() << "\"" << std::endl; | |
3295 } | |
3296 } | |
3297 | |
3298 } else if (message.getMethod() == "save") { | |
3299 | |
3300 QString path; | |
3301 if (message.getArgCount() == 1 && | |
3302 message.getArg(0).canConvert(QVariant::String)) { | |
3303 path = message.getArg(0).toString(); | |
3304 if (QFileInfo(path).exists()) { | |
3305 std::cerr << "MainWindow::handleOSCMessage: Refusing to overwrite existing file in save" << std::endl; | |
3306 } else { | |
3307 saveSessionFile(path); | |
3308 } | |
3309 } | |
3310 | |
3311 } else if (message.getMethod() == "export") { | |
3312 | |
3313 QString path; | |
3314 if (getMainModel()) { | |
3315 if (message.getArgCount() == 1 && | |
3316 message.getArg(0).canConvert(QVariant::String)) { | |
3317 path = message.getArg(0).toString(); | |
3318 if (QFileInfo(path).exists()) { | |
3319 std::cerr << "MainWindow::handleOSCMessage: Refusing to overwrite existing file in export" << std::endl; | |
3320 } else { | |
3321 WavFileWriter writer(path, | |
3322 getMainModel()->getSampleRate(), | |
3323 getMainModel()->getChannelCount()); | |
3324 MultiSelection ms = m_viewManager->getSelection(); | |
3325 if (!ms.getSelections().empty()) { | |
3326 writer.writeModel(getMainModel(), &ms); | |
3327 } else { | |
3328 writer.writeModel(getMainModel()); | |
3329 } | |
3330 } | |
3331 } | |
3332 } | |
3333 | |
3334 } else if (message.getMethod() == "jump" || | |
3335 message.getMethod() == "play") { | |
3336 | |
3337 if (getMainModel()) { | |
3338 | |
3339 unsigned long frame = m_viewManager->getPlaybackFrame(); | |
3340 bool selection = false; | |
3341 bool play = (message.getMethod() == "play"); | |
3342 | |
3343 if (message.getArgCount() == 1) { | |
3344 | |
3345 if (message.getArg(0).canConvert(QVariant::String) && | |
3346 message.getArg(0).toString() == "selection") { | |
3347 | |
3348 selection = true; | |
3349 | |
3350 } else if (message.getArg(0).canConvert(QVariant::String) && | |
3351 message.getArg(0).toString() == "end") { | |
3352 | |
3353 frame = getMainModel()->getEndFrame(); | |
3354 | |
3355 } else if (message.getArg(0).canConvert(QVariant::Double)) { | |
3356 | |
3357 double time = message.getArg(0).toDouble(); | |
3358 if (time < 0.0) time = 0.0; | |
3359 | |
3360 frame = lrint(time * getMainModel()->getSampleRate()); | |
3361 } | |
3362 } | |
3363 | |
3364 if (frame > getMainModel()->getEndFrame()) { | |
3365 frame = getMainModel()->getEndFrame(); | |
3366 } | |
3367 | |
3368 if (play) { | |
3369 m_viewManager->setPlaySelectionMode(selection); | |
3370 } | |
3371 | |
3372 if (selection) { | |
3373 MultiSelection::SelectionList sl = m_viewManager->getSelections(); | |
3374 if (!sl.empty()) { | |
3375 frame = sl.begin()->getStartFrame(); | |
3376 } | |
3377 } | |
3378 | |
3379 m_viewManager->setPlaybackFrame(frame); | |
3380 | |
3381 if (play && !m_playSource->isPlaying()) { | |
3382 m_playSource->play(frame); | |
3383 } | |
3384 } | |
3385 | |
3386 } else if (message.getMethod() == "stop") { | |
3387 | |
3388 if (m_playSource->isPlaying()) m_playSource->stop(); | |
3389 | |
3390 } else if (message.getMethod() == "loop") { | |
3391 | |
3392 if (message.getArgCount() == 1 && | |
3393 message.getArg(0).canConvert(QVariant::String)) { | |
3394 | |
3395 QString str = message.getArg(0).toString(); | |
3396 if (str == "on") { | |
3397 m_viewManager->setPlayLoopMode(true); | |
3398 } else if (str == "off") { | |
3399 m_viewManager->setPlayLoopMode(false); | |
3400 } | |
3401 } | |
3402 | |
3403 } else if (message.getMethod() == "solo") { | |
3404 | |
3405 if (message.getArgCount() == 1 && | |
3406 message.getArg(0).canConvert(QVariant::String)) { | |
3407 | |
3408 QString str = message.getArg(0).toString(); | |
3409 if (str == "on") { | |
3410 m_viewManager->setPlaySoloMode(true); | |
3411 } else if (str == "off") { | |
3412 m_viewManager->setPlaySoloMode(false); | |
3413 } | |
3414 } | |
3415 | |
3416 } else if (message.getMethod() == "select" || | |
3417 message.getMethod() == "addselect") { | |
3418 | |
3419 if (getMainModel()) { | |
3420 | |
3421 int f0 = getMainModel()->getStartFrame(); | |
3422 int f1 = getMainModel()->getEndFrame(); | |
3423 | |
3424 bool done = false; | |
3425 | |
3426 if (message.getArgCount() == 2 && | |
3427 message.getArg(0).canConvert(QVariant::Double) && | |
3428 message.getArg(1).canConvert(QVariant::Double)) { | |
3429 | |
3430 double t0 = message.getArg(0).toDouble(); | |
3431 double t1 = message.getArg(1).toDouble(); | |
3432 if (t1 < t0) { double temp = t0; t0 = t1; t1 = temp; } | |
3433 if (t0 < 0.0) t0 = 0.0; | |
3434 if (t1 < 0.0) t1 = 0.0; | |
3435 | |
3436 f0 = lrint(t0 * getMainModel()->getSampleRate()); | |
3437 f1 = lrint(t1 * getMainModel()->getSampleRate()); | |
3438 | |
3439 Pane *pane = m_paneStack->getCurrentPane(); | |
3440 Layer *layer = 0; | |
3441 if (pane) layer = pane->getSelectedLayer(); | |
3442 if (layer) { | |
3443 size_t resolution; | |
3444 layer->snapToFeatureFrame(pane, f0, resolution, | |
3445 Layer::SnapLeft); | |
3446 layer->snapToFeatureFrame(pane, f1, resolution, | |
3447 Layer::SnapRight); | |
3448 } | |
3449 | |
3450 } else if (message.getArgCount() == 1 && | |
3451 message.getArg(0).canConvert(QVariant::String)) { | |
3452 | |
3453 QString str = message.getArg(0).toString(); | |
3454 if (str == "none") { | |
3455 m_viewManager->clearSelections(); | |
3456 done = true; | |
3457 } | |
3458 } | |
3459 | |
3460 if (!done) { | |
3461 if (message.getMethod() == "select") { | |
3462 m_viewManager->setSelection(Selection(f0, f1)); | |
3463 } else { | |
3464 m_viewManager->addSelection(Selection(f0, f1)); | |
3465 } | |
3466 } | |
3467 } | |
3468 | |
3469 } else if (message.getMethod() == "add") { | |
3470 | |
3471 if (getMainModel()) { | |
3472 | |
3473 if (message.getArgCount() >= 1 && | |
3474 message.getArg(0).canConvert(QVariant::String)) { | |
3475 | |
3476 int channel = -1; | |
3477 if (message.getArgCount() == 2 && | |
3478 message.getArg(0).canConvert(QVariant::Int)) { | |
3479 channel = message.getArg(0).toInt(); | |
3480 if (channel < -1 || | |
3481 channel > int(getMainModel()->getChannelCount())) { | |
3482 std::cerr << "WARNING: MainWindow::handleOSCMessage: channel " | |
3483 << channel << " out of range" << std::endl; | |
3484 channel = -1; | |
3485 } | |
3486 } | |
3487 | |
3488 QString str = message.getArg(0).toString(); | |
3489 | |
3490 LayerFactory::LayerType type = | |
3491 LayerFactory::getInstance()->getLayerTypeForName(str); | |
3492 | |
3493 if (type == LayerFactory::UnknownLayer) { | |
3494 std::cerr << "WARNING: MainWindow::handleOSCMessage: unknown layer " | |
3495 << "type " << str.toStdString() << std::endl; | |
3496 } else { | |
3497 | |
3498 PaneConfiguration configuration(type, | |
3499 getMainModel(), | |
3500 channel); | |
3501 | |
3502 addPane(configuration, | |
3503 tr("Add %1 Pane") | |
3504 .arg(LayerFactory::getInstance()-> | |
3505 getLayerPresentationName(type))); | |
3506 } | |
3507 } | |
3508 } | |
3509 | |
3510 } else if (message.getMethod() == "undo") { | |
3511 | |
3512 CommandHistory::getInstance()->undo(); | |
3513 | |
3514 } else if (message.getMethod() == "redo") { | |
3515 | |
3516 CommandHistory::getInstance()->redo(); | |
3517 | |
3518 } else if (message.getMethod() == "set") { | |
3519 | |
3520 if (message.getArgCount() == 2 && | |
3521 message.getArg(0).canConvert(QVariant::String) && | |
3522 message.getArg(1).canConvert(QVariant::Double)) { | |
3523 | |
3524 QString property = message.getArg(0).toString(); | |
3525 float value = (float)message.getArg(1).toDouble(); | |
3526 | |
3527 if (property == "gain") { | |
3528 if (value < 0.0) value = 0.0; | |
3529 m_fader->setValue(value); | |
3530 if (m_playTarget) m_playTarget->setOutputGain(value); | |
3531 } else if (property == "speedup") { | |
3532 m_playSpeed->setMappedValue(value); | |
3533 } else if (property == "overlays") { | |
3534 if (value < 0.5) { | |
3535 m_viewManager->setOverlayMode(ViewManager::NoOverlays); | |
3536 } else if (value < 1.5) { | |
3537 m_viewManager->setOverlayMode(ViewManager::MinimalOverlays); | |
3538 } else if (value < 2.5) { | |
3539 m_viewManager->setOverlayMode(ViewManager::StandardOverlays); | |
3540 } else { | |
3541 m_viewManager->setOverlayMode(ViewManager::AllOverlays); | |
3542 } | |
3543 } else if (property == "zoomwheels") { | |
3544 m_viewManager->setZoomWheelsEnabled(value > 0.5); | |
3545 } else if (property == "propertyboxes") { | |
3546 bool toggle = ((value < 0.5) != | |
3547 (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks)); | |
3548 if (toggle) togglePropertyBoxes(); | |
3549 } | |
3550 | |
3551 } else { | |
3552 PropertyContainer *container = 0; | |
3553 Pane *pane = m_paneStack->getCurrentPane(); | |
3554 if (pane && | |
3555 message.getArgCount() == 3 && | |
3556 message.getArg(0).canConvert(QVariant::String) && | |
3557 message.getArg(1).canConvert(QVariant::String) && | |
3558 message.getArg(2).canConvert(QVariant::String)) { | |
3559 if (message.getArg(0).toString() == "pane") { | |
3560 container = pane->getPropertyContainer(0); | |
3561 } else if (message.getArg(0).toString() == "layer") { | |
3562 container = pane->getSelectedLayer(); | |
3563 } | |
3564 } | |
3565 if (container) { | |
3566 QString nameString = message.getArg(1).toString(); | |
3567 QString valueString = message.getArg(2).toString(); | |
3568 container->setPropertyWithCommand(nameString, valueString); | |
3569 } | |
3570 } | |
3571 | |
3572 } else if (message.getMethod() == "setcurrent") { | |
3573 | |
3574 int paneIndex = -1, layerIndex = -1; | |
3575 bool wantLayer = false; | |
3576 | |
3577 if (message.getArgCount() >= 1 && | |
3578 message.getArg(0).canConvert(QVariant::Int)) { | |
3579 | |
3580 paneIndex = message.getArg(0).toInt() - 1; | |
3581 | |
3582 if (message.getArgCount() >= 2 && | |
3583 message.getArg(1).canConvert(QVariant::Int)) { | |
3584 wantLayer = true; | |
3585 layerIndex = message.getArg(1).toInt() - 1; | |
3586 } | |
3587 } | |
3588 | |
3589 if (paneIndex >= 0 && paneIndex < m_paneStack->getPaneCount()) { | |
3590 Pane *pane = m_paneStack->getPane(paneIndex); | |
3591 m_paneStack->setCurrentPane(pane); | |
3592 if (layerIndex >= 0 && layerIndex < pane->getLayerCount()) { | |
3593 Layer *layer = pane->getLayer(layerIndex); | |
3594 m_paneStack->setCurrentLayer(pane, layer); | |
3595 } else if (wantLayer && layerIndex == -1) { | |
3596 m_paneStack->setCurrentLayer(pane, 0); | |
3597 } | |
3598 } | |
3599 | |
3600 } else if (message.getMethod() == "delete") { | |
3601 | |
3602 if (message.getArgCount() == 1 && | |
3603 message.getArg(0).canConvert(QVariant::String)) { | |
3604 | |
3605 QString target = message.getArg(0).toString(); | |
3606 | |
3607 if (target == "pane") { | |
3608 | |
3609 deleteCurrentPane(); | |
3610 | |
3611 } else if (target == "layer") { | |
3612 | |
3613 deleteCurrentLayer(); | |
3614 | |
3615 } else { | |
3616 | |
3617 std::cerr << "WARNING: MainWindow::handleOSCMessage: Unknown delete target " << target.toStdString() << std::endl; | |
3618 } | |
3619 } | |
3620 | |
3621 } else if (message.getMethod() == "zoom") { | |
3622 | |
3623 if (message.getArgCount() == 1) { | |
3624 if (message.getArg(0).canConvert(QVariant::String) && | |
3625 message.getArg(0).toString() == "in") { | |
3626 zoomIn(); | |
3627 } else if (message.getArg(0).canConvert(QVariant::String) && | |
3628 message.getArg(0).toString() == "out") { | |
3629 zoomOut(); | |
3630 } else if (message.getArg(0).canConvert(QVariant::String) && | |
3631 message.getArg(0).toString() == "default") { | |
3632 zoomDefault(); | |
3633 } else if (message.getArg(0).canConvert(QVariant::Double)) { | |
3634 double level = message.getArg(0).toDouble(); | |
3635 Pane *currentPane = m_paneStack->getCurrentPane(); | |
3636 if (level < 1.0) level = 1.0; | |
3637 if (currentPane) currentPane->setZoomLevel(lrint(level)); | |
3638 } | |
3639 } | |
3640 | |
3641 } else if (message.getMethod() == "zoomvertical") { | |
3642 | |
3643 Pane *pane = m_paneStack->getCurrentPane(); | |
3644 Layer *layer = 0; | |
3645 if (pane && pane->getLayerCount() > 0) { | |
3646 layer = pane->getLayer(pane->getLayerCount() - 1); | |
3647 } | |
3648 int defaultStep = 0; | |
3649 int steps = 0; | |
3650 if (layer) { | |
3651 steps = layer->getVerticalZoomSteps(defaultStep); | |
3652 if (message.getArgCount() == 1 && steps > 0) { | |
3653 if (message.getArg(0).canConvert(QVariant::String) && | |
3654 message.getArg(0).toString() == "in") { | |
3655 int step = layer->getCurrentVerticalZoomStep() + 1; | |
3656 if (step < steps) layer->setVerticalZoomStep(step); | |
3657 } else if (message.getArg(0).canConvert(QVariant::String) && | |
3658 message.getArg(0).toString() == "out") { | |
3659 int step = layer->getCurrentVerticalZoomStep() - 1; | |
3660 if (step >= 0) layer->setVerticalZoomStep(step); | |
3661 } else if (message.getArg(0).canConvert(QVariant::String) && | |
3662 message.getArg(0).toString() == "default") { | |
3663 layer->setVerticalZoomStep(defaultStep); | |
3664 } | |
3665 } else if (message.getArgCount() == 2) { | |
3666 if (message.getArg(0).canConvert(QVariant::Double) && | |
3667 message.getArg(1).canConvert(QVariant::Double)) { | |
3668 double min = message.getArg(0).toDouble(); | |
3669 double max = message.getArg(1).toDouble(); | |
3670 layer->setDisplayExtents(min, max); | |
3671 } | |
3672 } | |
3673 } | |
3674 | |
3675 } else if (message.getMethod() == "quit") { | |
3676 | |
3677 m_abandoning = true; | |
3678 close(); | |
3679 | |
3680 } else if (message.getMethod() == "resize") { | |
3681 | |
3682 if (message.getArgCount() == 2) { | |
3683 | |
3684 int width = 0, height = 0; | |
3685 | |
3686 if (message.getArg(1).canConvert(QVariant::Int)) { | |
3687 | |
3688 height = message.getArg(1).toInt(); | |
3689 | |
3690 if (message.getArg(0).canConvert(QVariant::String) && | |
3691 message.getArg(0).toString() == "pane") { | |
3692 | |
3693 Pane *pane = m_paneStack->getCurrentPane(); | |
3694 if (pane) pane->resize(pane->width(), height); | |
3695 | |
3696 } else if (message.getArg(0).canConvert(QVariant::Int)) { | |
3697 | |
3698 width = message.getArg(0).toInt(); | |
3699 resize(width, height); | |
3700 } | |
3701 } | |
3702 } | |
3703 | |
3704 } else if (message.getMethod() == "transform") { | |
3705 | |
3706 Pane *pane = m_paneStack->getCurrentPane(); | |
3707 | |
3708 if (getMainModel() && | |
3709 pane && | |
3710 message.getArgCount() == 1 && | |
3711 message.getArg(0).canConvert(QVariant::String)) { | |
3712 | |
3713 TransformId transform = message.getArg(0).toString(); | |
3714 | |
3715 Layer *newLayer = m_document->createDerivedLayer | |
3716 (transform, | |
3717 getMainModel(), | |
3718 ModelTransformerFactory::getInstance()->getDefaultContextForTransformer | |
3719 (transform, getMainModel()), | |
3720 ""); | |
3721 | |
3722 if (newLayer) { | |
3723 m_document->addLayerToView(pane, newLayer); | |
3724 m_recentTransforms.add(transform); | |
3725 m_paneStack->setCurrentLayer(pane, newLayer); | |
3726 } | |
3727 } | |
3728 | |
3729 } else { | |
3730 std::cerr << "WARNING: MainWindow::handleOSCMessage: Unknown or unsupported " | |
3731 << "method \"" << message.getMethod().toStdString() | |
3732 << "\"" << std::endl; | |
3733 } | |
3734 | |
3735 } | 3248 } |
3736 | 3249 |
3737 void | 3250 void |
3738 MainWindow::preferences() | 3251 MainWindow::preferences() |
3739 { | 3252 { |