Mercurial > hg > sonic-visualiser
comparison main/MainWindow.cpp @ 209:55a4719c8e7d
* Introduce new Transform class which contains data necessary to describe the
context for a plugin -- the plugin's name and output, the step/block size
etc (formerly spread across ExecutionContext and TransformFactory). Other
code hasn't been updated to use this yet.
* Rename existing Transform stuff to Transformers (because they run Transforms)
I'm still not 100% sure about this change, don't rely on it.
author | Chris Cannam |
---|---|
date | Mon, 05 Nov 2007 15:31:06 +0000 |
parents | 0b4d563d7469 |
children | 92306bafbbe6 |
comparison
equal
deleted
inserted
replaced
208:0b4d563d7469 | 209:55a4719c8e7d |
---|---|
58 #include "data/fileio/MIDIFileWriter.h" | 58 #include "data/fileio/MIDIFileWriter.h" |
59 #include "data/fileio/BZipFileDevice.h" | 59 #include "data/fileio/BZipFileDevice.h" |
60 #include "data/fileio/FileSource.h" | 60 #include "data/fileio/FileSource.h" |
61 #include "data/fft/FFTDataServer.h" | 61 #include "data/fft/FFTDataServer.h" |
62 #include "base/RecentFiles.h" | 62 #include "base/RecentFiles.h" |
63 #include "plugin/transform/TransformFactory.h" | 63 #include "plugin/transform/TransformerFactory.h" |
64 #include "base/PlayParameterRepository.h" | 64 #include "base/PlayParameterRepository.h" |
65 #include "base/XmlExportable.h" | 65 #include "base/XmlExportable.h" |
66 #include "base/CommandHistory.h" | 66 #include "base/CommandHistory.h" |
67 #include "base/Profiler.h" | 67 #include "base/Profiler.h" |
68 #include "base/Clipboard.h" | 68 #include "base/Clipboard.h" |
120 m_transformsMenu(0), | 120 m_transformsMenu(0), |
121 m_playbackMenu(0), | 121 m_playbackMenu(0), |
122 m_existingLayersMenu(0), | 122 m_existingLayersMenu(0), |
123 m_sliceMenu(0), | 123 m_sliceMenu(0), |
124 m_recentFilesMenu(0), | 124 m_recentFilesMenu(0), |
125 m_recentTransformsMenu(0), | 125 m_recentTransformersMenu(0), |
126 m_rightButtonMenu(0), | 126 m_rightButtonMenu(0), |
127 m_rightButtonLayerMenu(0), | 127 m_rightButtonLayerMenu(0), |
128 m_rightButtonTransformsMenu(0), | 128 m_rightButtonTransformersMenu(0), |
129 m_rightButtonPlaybackMenu(0), | 129 m_rightButtonPlaybackMenu(0), |
130 m_soloAction(0), | 130 m_soloAction(0), |
131 m_soloModified(false), | 131 m_soloModified(false), |
132 m_prevSolo(false), | 132 m_prevSolo(false), |
133 m_ffwdAction(0), | 133 m_ffwdAction(0), |
301 m_rightButtonLayerMenu = m_rightButtonMenu->addMenu(tr("&Layer")); | 301 m_rightButtonLayerMenu = m_rightButtonMenu->addMenu(tr("&Layer")); |
302 m_rightButtonLayerMenu->setTearOffEnabled(true); | 302 m_rightButtonLayerMenu->setTearOffEnabled(true); |
303 m_rightButtonMenu->addSeparator(); | 303 m_rightButtonMenu->addSeparator(); |
304 } | 304 } |
305 | 305 |
306 if (m_rightButtonTransformsMenu) { | 306 if (m_rightButtonTransformersMenu) { |
307 m_rightButtonTransformsMenu->clear(); | 307 m_rightButtonTransformersMenu->clear(); |
308 } else { | 308 } else { |
309 m_rightButtonTransformsMenu = m_rightButtonMenu->addMenu(tr("&Transform")); | 309 m_rightButtonTransformersMenu = m_rightButtonMenu->addMenu(tr("&Transformer")); |
310 m_rightButtonTransformsMenu->setTearOffEnabled(true); | 310 m_rightButtonTransformersMenu->setTearOffEnabled(true); |
311 m_rightButtonMenu->addSeparator(); | 311 m_rightButtonMenu->addSeparator(); |
312 } | 312 } |
313 | 313 |
314 if (!m_mainMenusCreated) { | 314 if (!m_mainMenusCreated) { |
315 CommandHistory::getInstance()->registerMenu(m_rightButtonMenu); | 315 CommandHistory::getInstance()->registerMenu(m_rightButtonMenu); |
318 | 318 |
319 setupFileMenu(); | 319 setupFileMenu(); |
320 setupEditMenu(); | 320 setupEditMenu(); |
321 setupViewMenu(); | 321 setupViewMenu(); |
322 setupPaneAndLayerMenus(); | 322 setupPaneAndLayerMenus(); |
323 setupTransformsMenu(); | 323 setupTransformersMenu(); |
324 | 324 |
325 m_mainMenusCreated = true; | 325 m_mainMenusCreated = true; |
326 } | 326 } |
327 | 327 |
328 void | 328 void |
898 LayerFactory::PeakFrequencySpectrogram, | 898 LayerFactory::PeakFrequencySpectrogram, |
899 LayerFactory::Spectrum | 899 LayerFactory::Spectrum |
900 }; | 900 }; |
901 | 901 |
902 std::vector<Model *> models; | 902 std::vector<Model *> models; |
903 if (m_document) models = m_document->getTransformInputModels(); //!!! not well named for this! | 903 if (m_document) models = m_document->getTransformerInputModels(); //!!! not well named for this! |
904 bool plural = (models.size() > 1); | 904 bool plural = (models.size() > 1); |
905 if (models.empty()) { | 905 if (models.empty()) { |
906 models.push_back(getMainModel()); // probably 0 | 906 models.push_back(getMainModel()); // probably 0 |
907 } | 907 } |
908 | 908 |
1159 | 1159 |
1160 m_keyReference->registerShortcut(raction); // rename after delete, so delete layer goes next to delete pane | 1160 m_keyReference->registerShortcut(raction); // rename after delete, so delete layer goes next to delete pane |
1161 } | 1161 } |
1162 | 1162 |
1163 void | 1163 void |
1164 MainWindow::setupTransformsMenu() | 1164 MainWindow::setupTransformersMenu() |
1165 { | 1165 { |
1166 if (m_transformsMenu) { | 1166 if (m_transformsMenu) { |
1167 m_transformActions.clear(); | 1167 m_transformActions.clear(); |
1168 m_transformActionsReverse.clear(); | 1168 m_transformActionsReverse.clear(); |
1169 m_transformsMenu->clear(); | 1169 m_transformsMenu->clear(); |
1170 } else { | 1170 } else { |
1171 m_transformsMenu = menuBar()->addMenu(tr("&Transform")); | 1171 m_transformsMenu = menuBar()->addMenu(tr("&Transform")); |
1172 m_transformsMenu->setTearOffEnabled(true); | 1172 m_transformsMenu->setTearOffEnabled(true); |
1173 } | 1173 } |
1174 | 1174 |
1175 TransformFactory::TransformList transforms = | 1175 TransformerFactory::TransformerList transforms = |
1176 TransformFactory::getInstance()->getAllTransforms(); | 1176 TransformerFactory::getInstance()->getAllTransformers(); |
1177 | 1177 |
1178 vector<QString> types = | 1178 vector<QString> types = |
1179 TransformFactory::getInstance()->getAllTransformTypes(); | 1179 TransformerFactory::getInstance()->getAllTransformerTypes(); |
1180 | 1180 |
1181 map<QString, map<QString, SubdividingMenu *> > categoryMenus; | 1181 map<QString, map<QString, SubdividingMenu *> > categoryMenus; |
1182 map<QString, map<QString, SubdividingMenu *> > makerMenus; | 1182 map<QString, map<QString, SubdividingMenu *> > makerMenus; |
1183 | 1183 |
1184 map<QString, SubdividingMenu *> byPluginNameMenus; | 1184 map<QString, SubdividingMenu *> byPluginNameMenus; |
1185 map<QString, map<QString, QMenu *> > pluginNameMenus; | 1185 map<QString, map<QString, QMenu *> > pluginNameMenus; |
1186 | 1186 |
1187 set<SubdividingMenu *> pendingMenus; | 1187 set<SubdividingMenu *> pendingMenus; |
1188 | 1188 |
1189 m_recentTransformsMenu = m_transformsMenu->addMenu(tr("&Recent Transforms")); | 1189 m_recentTransformersMenu = m_transformsMenu->addMenu(tr("&Recent Transforms")); |
1190 m_recentTransformsMenu->setTearOffEnabled(true); | 1190 m_recentTransformersMenu->setTearOffEnabled(true); |
1191 m_rightButtonTransformsMenu->addMenu(m_recentTransformsMenu); | 1191 m_rightButtonTransformersMenu->addMenu(m_recentTransformersMenu); |
1192 connect(&m_recentTransforms, SIGNAL(recentChanged()), | 1192 connect(&m_recentTransformers, SIGNAL(recentChanged()), |
1193 this, SLOT(setupRecentTransformsMenu())); | 1193 this, SLOT(setupRecentTransformersMenu())); |
1194 | 1194 |
1195 m_transformsMenu->addSeparator(); | 1195 m_transformsMenu->addSeparator(); |
1196 m_rightButtonTransformsMenu->addSeparator(); | 1196 m_rightButtonTransformersMenu->addSeparator(); |
1197 | 1197 |
1198 for (vector<QString>::iterator i = types.begin(); i != types.end(); ++i) { | 1198 for (vector<QString>::iterator i = types.begin(); i != types.end(); ++i) { |
1199 | 1199 |
1200 if (i != types.begin()) { | 1200 if (i != types.begin()) { |
1201 m_transformsMenu->addSeparator(); | 1201 m_transformsMenu->addSeparator(); |
1202 m_rightButtonTransformsMenu->addSeparator(); | 1202 m_rightButtonTransformersMenu->addSeparator(); |
1203 } | 1203 } |
1204 | 1204 |
1205 QString byCategoryLabel = tr("%1 by Category").arg(*i); | 1205 QString byCategoryLabel = tr("%1 by Category").arg(*i); |
1206 SubdividingMenu *byCategoryMenu = new SubdividingMenu(byCategoryLabel, | 1206 SubdividingMenu *byCategoryMenu = new SubdividingMenu(byCategoryLabel, |
1207 20, 40); | 1207 20, 40); |
1208 byCategoryMenu->setTearOffEnabled(true); | 1208 byCategoryMenu->setTearOffEnabled(true); |
1209 m_transformsMenu->addMenu(byCategoryMenu); | 1209 m_transformsMenu->addMenu(byCategoryMenu); |
1210 m_rightButtonTransformsMenu->addMenu(byCategoryMenu); | 1210 m_rightButtonTransformersMenu->addMenu(byCategoryMenu); |
1211 pendingMenus.insert(byCategoryMenu); | 1211 pendingMenus.insert(byCategoryMenu); |
1212 | 1212 |
1213 vector<QString> categories = | 1213 vector<QString> categories = |
1214 TransformFactory::getInstance()->getTransformCategories(*i); | 1214 TransformerFactory::getInstance()->getTransformerCategories(*i); |
1215 | 1215 |
1216 for (vector<QString>::iterator j = categories.begin(); | 1216 for (vector<QString>::iterator j = categories.begin(); |
1217 j != categories.end(); ++j) { | 1217 j != categories.end(); ++j) { |
1218 | 1218 |
1219 QString category = *j; | 1219 QString category = *j; |
1250 | 1250 |
1251 QString byPluginNameLabel = tr("%1 by Plugin Name").arg(*i); | 1251 QString byPluginNameLabel = tr("%1 by Plugin Name").arg(*i); |
1252 byPluginNameMenus[*i] = new SubdividingMenu(byPluginNameLabel); | 1252 byPluginNameMenus[*i] = new SubdividingMenu(byPluginNameLabel); |
1253 byPluginNameMenus[*i]->setTearOffEnabled(true); | 1253 byPluginNameMenus[*i]->setTearOffEnabled(true); |
1254 m_transformsMenu->addMenu(byPluginNameMenus[*i]); | 1254 m_transformsMenu->addMenu(byPluginNameMenus[*i]); |
1255 m_rightButtonTransformsMenu->addMenu(byPluginNameMenus[*i]); | 1255 m_rightButtonTransformersMenu->addMenu(byPluginNameMenus[*i]); |
1256 pendingMenus.insert(byPluginNameMenus[*i]); | 1256 pendingMenus.insert(byPluginNameMenus[*i]); |
1257 | 1257 |
1258 QString byMakerLabel = tr("%1 by Maker").arg(*i); | 1258 QString byMakerLabel = tr("%1 by Maker").arg(*i); |
1259 SubdividingMenu *byMakerMenu = new SubdividingMenu(byMakerLabel, 20, 40); | 1259 SubdividingMenu *byMakerMenu = new SubdividingMenu(byMakerLabel, 20, 40); |
1260 byMakerMenu->setTearOffEnabled(true); | 1260 byMakerMenu->setTearOffEnabled(true); |
1261 m_transformsMenu->addMenu(byMakerMenu); | 1261 m_transformsMenu->addMenu(byMakerMenu); |
1262 m_rightButtonTransformsMenu->addMenu(byMakerMenu); | 1262 m_rightButtonTransformersMenu->addMenu(byMakerMenu); |
1263 pendingMenus.insert(byMakerMenu); | 1263 pendingMenus.insert(byMakerMenu); |
1264 | 1264 |
1265 vector<QString> makers = | 1265 vector<QString> makers = |
1266 TransformFactory::getInstance()->getTransformMakers(*i); | 1266 TransformerFactory::getInstance()->getTransformerMakers(*i); |
1267 | 1267 |
1268 for (vector<QString>::iterator j = makers.begin(); | 1268 for (vector<QString>::iterator j = makers.begin(); |
1269 j != makers.end(); ++j) { | 1269 j != makers.end(); ++j) { |
1270 | 1270 |
1271 QString maker = *j; | 1271 QString maker = *j; |
1328 connect(action, SIGNAL(triggered()), this, SLOT(addLayer())); | 1328 connect(action, SIGNAL(triggered()), this, SLOT(addLayer())); |
1329 m_transformActions[action] = transforms[i].identifier; | 1329 m_transformActions[action] = transforms[i].identifier; |
1330 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool))); | 1330 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool))); |
1331 action->setStatusTip(transforms[i].description); | 1331 action->setStatusTip(transforms[i].description); |
1332 | 1332 |
1333 // cerr << "Transform: \"" << name.toStdString() << "\": plugin name \"" << pluginName.toStdString() << "\"" << endl; | 1333 // cerr << "Transformer: \"" << name.toStdString() << "\": plugin name \"" << pluginName.toStdString() << "\"" << endl; |
1334 | 1334 |
1335 if (pluginNameMenus[type].find(pluginName) == | 1335 if (pluginNameMenus[type].find(pluginName) == |
1336 pluginNameMenus[type].end()) { | 1336 pluginNameMenus[type].end()) { |
1337 | 1337 |
1338 SubdividingMenu *parentMenu = byPluginNameMenus[type]; | 1338 SubdividingMenu *parentMenu = byPluginNameMenus[type]; |
1358 for (set<SubdividingMenu *>::iterator i = pendingMenus.begin(); | 1358 for (set<SubdividingMenu *>::iterator i = pendingMenus.begin(); |
1359 i != pendingMenus.end(); ++i) { | 1359 i != pendingMenus.end(); ++i) { |
1360 (*i)->entriesAdded(); | 1360 (*i)->entriesAdded(); |
1361 } | 1361 } |
1362 | 1362 |
1363 setupRecentTransformsMenu(); | 1363 setupRecentTransformersMenu(); |
1364 } | 1364 } |
1365 | 1365 |
1366 void | 1366 void |
1367 MainWindow::setupHelpMenu() | 1367 MainWindow::setupHelpMenu() |
1368 { | 1368 { |
1417 m_recentFilesMenu->addAction(action); | 1417 m_recentFilesMenu->addAction(action); |
1418 } | 1418 } |
1419 } | 1419 } |
1420 | 1420 |
1421 void | 1421 void |
1422 MainWindow::setupRecentTransformsMenu() | 1422 MainWindow::setupRecentTransformersMenu() |
1423 { | 1423 { |
1424 m_recentTransformsMenu->clear(); | 1424 m_recentTransformersMenu->clear(); |
1425 vector<QString> transforms = m_recentTransforms.getRecent(); | 1425 vector<QString> transforms = m_recentTransformers.getRecent(); |
1426 for (size_t i = 0; i < transforms.size(); ++i) { | 1426 for (size_t i = 0; i < transforms.size(); ++i) { |
1427 TransformActionReverseMap::iterator ti = | 1427 TransformerActionReverseMap::iterator ti = |
1428 m_transformActionsReverse.find(transforms[i]); | 1428 m_transformActionsReverse.find(transforms[i]); |
1429 if (ti == m_transformActionsReverse.end()) { | 1429 if (ti == m_transformActionsReverse.end()) { |
1430 std::cerr << "WARNING: MainWindow::setupRecentTransformsMenu: " | 1430 std::cerr << "WARNING: MainWindow::setupRecentTransformersMenu: " |
1431 << "Unknown transform \"" << transforms[i].toStdString() | 1431 << "Unknown transform \"" << transforms[i].toStdString() |
1432 << "\" in recent transforms list" << std::endl; | 1432 << "\" in recent transforms list" << std::endl; |
1433 continue; | 1433 continue; |
1434 } | 1434 } |
1435 if (i == 0) { | 1435 if (i == 0) { |
1436 ti->second->setShortcut(tr("Ctrl+T")); | 1436 ti->second->setShortcut(tr("Ctrl+T")); |
1437 m_keyReference->registerShortcut | 1437 m_keyReference->registerShortcut |
1438 (tr("Repeat Transform"), | 1438 (tr("Repeat Transformer"), |
1439 ti->second->shortcut(), | 1439 ti->second->shortcut(), |
1440 tr("Re-select the most recently run transform")); | 1440 tr("Re-select the most recently run transform")); |
1441 } | 1441 } |
1442 m_recentTransformsMenu->addAction(ti->second); | 1442 m_recentTransformersMenu->addAction(ti->second); |
1443 } | 1443 } |
1444 } | 1444 } |
1445 | 1445 |
1446 void | 1446 void |
1447 MainWindow::setupExistingLayersMenus() | 1447 MainWindow::setupExistingLayersMenus() |
2716 Model *model = 0; | 2716 Model *model = 0; |
2717 | 2717 |
2718 if (suggestedModel) { | 2718 if (suggestedModel) { |
2719 | 2719 |
2720 // check its validity | 2720 // check its validity |
2721 std::vector<Model *> inputModels = m_document->getTransformInputModels(); | 2721 std::vector<Model *> inputModels = m_document->getTransformerInputModels(); |
2722 for (size_t j = 0; j < inputModels.size(); ++j) { | 2722 for (size_t j = 0; j < inputModels.size(); ++j) { |
2723 if (inputModels[j] == suggestedModel) { | 2723 if (inputModels[j] == suggestedModel) { |
2724 model = suggestedModel; | 2724 model = suggestedModel; |
2725 break; | 2725 break; |
2726 } | 2726 } |
2798 m_document->addLayerToView(pane, newLayer); | 2798 m_document->addLayerToView(pane, newLayer); |
2799 m_paneStack->setCurrentLayer(pane, newLayer); | 2799 m_paneStack->setCurrentLayer(pane, newLayer); |
2800 return; | 2800 return; |
2801 } | 2801 } |
2802 | 2802 |
2803 TransformActionMap::iterator i = m_transformActions.find(action); | 2803 TransformerActionMap::iterator i = m_transformActions.find(action); |
2804 | 2804 |
2805 if (i == m_transformActions.end()) { | 2805 if (i == m_transformActions.end()) { |
2806 | 2806 |
2807 LayerActionMap::iterator i = m_layerActions.find(action); | 2807 LayerActionMap::iterator i = m_layerActions.find(action); |
2808 | 2808 |
2833 m_paneStack->setCurrentLayer(pane, newLayer); | 2833 m_paneStack->setCurrentLayer(pane, newLayer); |
2834 | 2834 |
2835 return; | 2835 return; |
2836 } | 2836 } |
2837 | 2837 |
2838 TransformId transform = i->second; | 2838 TransformerId transform = i->second; |
2839 TransformFactory *factory = TransformFactory::getInstance(); | 2839 TransformerFactory *factory = TransformerFactory::getInstance(); |
2840 | 2840 |
2841 QString configurationXml; | 2841 QString configurationXml; |
2842 | 2842 |
2843 int channel = -1; | 2843 int channel = -1; |
2844 // pick up the default channel from any existing layers on the same pane | 2844 // pick up the default channel from any existing layers on the same pane |
2852 | 2852 |
2853 // We always ask for configuration, even if the plugin isn't | 2853 // We always ask for configuration, even if the plugin isn't |
2854 // supposed to be configurable, because we need to let the user | 2854 // supposed to be configurable, because we need to let the user |
2855 // change the execution context (block size etc). | 2855 // change the execution context (block size etc). |
2856 | 2856 |
2857 PluginTransform::ExecutionContext context(channel); | 2857 PluginTransformer::ExecutionContext context(channel); |
2858 | 2858 |
2859 std::vector<Model *> candidateInputModels = | 2859 std::vector<Model *> candidateInputModels = |
2860 m_document->getTransformInputModels(); | 2860 m_document->getTransformerInputModels(); |
2861 | 2861 |
2862 size_t startFrame = 0, duration = 0; | 2862 size_t startFrame = 0, duration = 0; |
2863 size_t endFrame = 0; | 2863 size_t endFrame = 0; |
2864 m_viewManager->getSelection().getExtents(startFrame, endFrame); | 2864 m_viewManager->getSelection().getExtents(startFrame, endFrame); |
2865 if (endFrame > startFrame) duration = endFrame - startFrame; | 2865 if (endFrame > startFrame) duration = endFrame - startFrame; |
2866 else startFrame = 0; | 2866 else startFrame = 0; |
2867 | 2867 |
2868 Model *inputModel = factory->getConfigurationForTransform(transform, | 2868 Model *inputModel = factory->getConfigurationForTransformer(transform, |
2869 candidateInputModels, | 2869 candidateInputModels, |
2870 context, | 2870 context, |
2871 configurationXml, | 2871 configurationXml, |
2872 m_playSource, | 2872 m_playSource, |
2873 startFrame, | 2873 startFrame, |
2882 configurationXml); | 2882 configurationXml); |
2883 | 2883 |
2884 if (newLayer) { | 2884 if (newLayer) { |
2885 m_document->addLayerToView(pane, newLayer); | 2885 m_document->addLayerToView(pane, newLayer); |
2886 m_document->setChannel(newLayer, context.channel); | 2886 m_document->setChannel(newLayer, context.channel); |
2887 m_recentTransforms.add(transform); | 2887 m_recentTransformers.add(transform); |
2888 m_paneStack->setCurrentLayer(pane, newLayer); | 2888 m_paneStack->setCurrentLayer(pane, newLayer); |
2889 } | 2889 } |
2890 | 2890 |
2891 updateMenuStates(); | 2891 updateMenuStates(); |
2892 } | 2892 } |
3705 if (getMainModel() && | 3705 if (getMainModel() && |
3706 pane && | 3706 pane && |
3707 message.getArgCount() == 1 && | 3707 message.getArgCount() == 1 && |
3708 message.getArg(0).canConvert(QVariant::String)) { | 3708 message.getArg(0).canConvert(QVariant::String)) { |
3709 | 3709 |
3710 TransformId transform = message.getArg(0).toString(); | 3710 TransformerId transform = message.getArg(0).toString(); |
3711 | 3711 |
3712 Layer *newLayer = m_document->createDerivedLayer | 3712 Layer *newLayer = m_document->createDerivedLayer |
3713 (transform, | 3713 (transform, |
3714 getMainModel(), | 3714 getMainModel(), |
3715 TransformFactory::getInstance()->getDefaultContextForTransform | 3715 TransformerFactory::getInstance()->getDefaultContextForTransformer |
3716 (transform, getMainModel()), | 3716 (transform, getMainModel()), |
3717 ""); | 3717 ""); |
3718 | 3718 |
3719 if (newLayer) { | 3719 if (newLayer) { |
3720 m_document->addLayerToView(pane, newLayer); | 3720 m_document->addLayerToView(pane, newLayer); |
3721 m_recentTransforms.add(transform); | 3721 m_recentTransformers.add(transform); |
3722 m_paneStack->setCurrentLayer(pane, newLayer); | 3722 m_paneStack->setCurrentLayer(pane, newLayer); |
3723 } | 3723 } |
3724 } | 3724 } |
3725 | 3725 |
3726 } else { | 3726 } else { |