comparison main/MainWindow.cpp @ 197:c08c312b2399

* Make RemoteFile far more pervasive, and use it for local files as well so that we can handle both transparently. Make it shallow copy with reference counting, so it can be used by value without having to worry about the cache file lifetime. Use RemoteFile for MainWindow file-open functions, etc
author Chris Cannam
date Thu, 18 Oct 2007 15:31:20 +0000
parents 61bf55e80080
children 24ac2e4010c5
comparison
equal deleted inserted replaced
196:29c356da4ae4 197:c08c312b2399
2523 MainWindow::importAudio() 2523 MainWindow::importAudio()
2524 { 2524 {
2525 QString path = getOpenFileName(FileFinder::AudioFile); 2525 QString path = getOpenFileName(FileFinder::AudioFile);
2526 2526
2527 if (path != "") { 2527 if (path != "") {
2528 if (openAudioFile(path, ReplaceMainModel) == FileOpenFailed) { 2528 if (openAudio(path, ReplaceMainModel) == FileOpenFailed) {
2529 QMessageBox::critical(this, tr("Failed to open file"), 2529 QMessageBox::critical(this, tr("Failed to open file"),
2530 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path)); 2530 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path));
2531 } 2531 }
2532 } 2532 }
2533 } 2533 }
2536 MainWindow::importMoreAudio() 2536 MainWindow::importMoreAudio()
2537 { 2537 {
2538 QString path = getOpenFileName(FileFinder::AudioFile); 2538 QString path = getOpenFileName(FileFinder::AudioFile);
2539 2539
2540 if (path != "") { 2540 if (path != "") {
2541 if (openAudioFile(path, CreateAdditionalModel) == FileOpenFailed) { 2541 if (openAudio(path, CreateAdditionalModel) == FileOpenFailed) {
2542 QMessageBox::critical(this, tr("Failed to open file"), 2542 QMessageBox::critical(this, tr("Failed to open file"),
2543 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path)); 2543 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path));
2544 } 2544 }
2545 } 2545 }
2546 } 2546 }
2671 2671
2672 QString path = getOpenFileName(FileFinder::LayerFile); 2672 QString path = getOpenFileName(FileFinder::LayerFile);
2673 2673
2674 if (path != "") { 2674 if (path != "") {
2675 2675
2676 FileOpenStatus status = openLayerFile(path); 2676 FileOpenStatus status = openLayer(path);
2677 2677
2678 if (status == FileOpenFailed) { 2678 if (status == FileOpenFailed) {
2679 QMessageBox::critical(this, tr("Failed to open file"), 2679 QMessageBox::critical(this, tr("Failed to open file"),
2680 tr("<b>File open failed</b><p>Layer file %1 could not be opened.").arg(path)); 2680 tr("<b>File open failed</b><p>Layer file %1 could not be opened.").arg(path));
2681 return; 2681 return;
2682 } else if (status == FileOpenWrongMode) { 2682 } else if (status == FileOpenWrongMode) {
2683 QMessageBox::critical(this, tr("Failed to open file"), 2683 QMessageBox::critical(this, tr("Failed to open file"),
2684 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data")); 2684 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
2685 } 2685 }
2686 }
2687 }
2688
2689 MainWindow::FileOpenStatus
2690 MainWindow::openLayerFile(QString path)
2691 {
2692 return openLayerFile(path, path);
2693 }
2694
2695 MainWindow::FileOpenStatus
2696 MainWindow::openLayerFile(QString path, QString location)
2697 {
2698 Pane *pane = m_paneStack->getCurrentPane();
2699
2700 if (!pane) {
2701 // shouldn't happen, as the menu action should have been disabled
2702 std::cerr << "WARNING: MainWindow::openLayerFile: no current pane" << std::endl;
2703 return FileOpenWrongMode;
2704 }
2705
2706 if (!getMainModel()) {
2707 // shouldn't happen, as the menu action should have been disabled
2708 std::cerr << "WARNING: MainWindow::openLayerFile: No main model -- hence no default sample rate available" << std::endl;
2709 return FileOpenWrongMode;
2710 }
2711
2712 bool realFile = (location == path);
2713
2714 if (path.endsWith(".svl") || path.endsWith(".xml")) {
2715
2716 PaneCallback callback(this);
2717 QFile file(path);
2718
2719 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
2720 std::cerr << "ERROR: MainWindow::openLayerFile("
2721 << location.toStdString()
2722 << "): Failed to open file for reading" << std::endl;
2723 return FileOpenFailed;
2724 }
2725
2726 SVFileReader reader(m_document, callback, location);
2727 reader.setCurrentPane(pane);
2728
2729 QXmlInputSource inputSource(&file);
2730 reader.parse(inputSource);
2731
2732 if (!reader.isOK()) {
2733 std::cerr << "ERROR: MainWindow::openLayerFile("
2734 << location.toStdString()
2735 << "): Failed to read XML file: "
2736 << reader.getErrorString().toStdString() << std::endl;
2737 return FileOpenFailed;
2738 }
2739
2740 m_recentFiles.addFile(location);
2741
2742 if (realFile) {
2743 registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog
2744 }
2745
2746 return FileOpenSucceeded;
2747
2748 } else {
2749
2750 try {
2751
2752 Model *model = DataFileReaderFactory::load
2753 (path, getMainModel()->getSampleRate());
2754
2755 if (model) {
2756
2757 Layer *newLayer = m_document->createImportedLayer(model);
2758
2759 if (newLayer) {
2760
2761 m_document->addLayerToView(pane, newLayer);
2762 m_recentFiles.addFile(location);
2763
2764 if (realFile) {
2765 registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog
2766 }
2767
2768 return FileOpenSucceeded;
2769 }
2770 }
2771 } catch (DataFileReaderFactory::Exception e) {
2772 if (e == DataFileReaderFactory::ImportCancelled) {
2773 return FileOpenCancelled;
2774 }
2775 }
2776 }
2777
2778 return FileOpenFailed;
2779 }
2780
2781 MainWindow::FileOpenStatus
2782 MainWindow::openImageFile(QString path)
2783 {
2784 return openImageFile(path, path);
2785 }
2786
2787 MainWindow::FileOpenStatus
2788 MainWindow::openImageFile(QString path, QString location)
2789 {
2790 Pane *pane = m_paneStack->getCurrentPane();
2791
2792 if (!pane) {
2793 // shouldn't happen, as the menu action should have been disabled
2794 std::cerr << "WARNING: MainWindow::openImageFile: no current pane" << std::endl;
2795 return FileOpenWrongMode;
2796 }
2797
2798 if (!m_document->getMainModel()) {
2799 return FileOpenWrongMode;
2800 }
2801
2802 bool newLayer = false;
2803
2804 ImageLayer *il = dynamic_cast<ImageLayer *>(pane->getSelectedLayer());
2805 if (!il) {
2806 for (int i = pane->getLayerCount()-1; i >= 0; --i) {
2807 il = dynamic_cast<ImageLayer *>(pane->getLayer(i));
2808 if (il) break;
2809 }
2810 }
2811 if (!il) {
2812 il = dynamic_cast<ImageLayer *>
2813 (m_document->createEmptyLayer(LayerFactory::Image));
2814 if (!il) return FileOpenFailed;
2815 newLayer = true;
2816 }
2817
2818 // We don't put the image file in Recent Files
2819
2820 std::cerr << "openImageFile: trying location \"" << location.toStdString() << "\" in image layer" << std::endl;
2821
2822 if (!il->addImage(m_viewManager->getGlobalCentreFrame(), location)) {
2823 if (newLayer) {
2824 m_document->setModel(il, 0); // releasing its model
2825 delete il;
2826 }
2827 return FileOpenFailed;
2828 } else {
2829 if (newLayer) {
2830 m_document->addLayerToView(pane, il);
2831 }
2832 m_paneStack->setCurrentLayer(pane, il);
2833 return FileOpenSucceeded;
2834 } 2686 }
2835 } 2687 }
2836 2688
2837 void 2689 void
2838 MainWindow::exportLayer() 2690 MainWindow::exportLayer()
3004 2856
3005 delete image; 2857 delete image;
3006 } 2858 }
3007 2859
3008 MainWindow::FileOpenStatus 2860 MainWindow::FileOpenStatus
3009 MainWindow::openAudioFile(QString path, AudioFileOpenMode mode) 2861 MainWindow::open(QString fileOrUrl, AudioFileOpenMode mode)
3010 { 2862 {
3011 return openAudioFile(path, path, mode); 2863 return open(RemoteFile(fileOrUrl), mode);
3012 } 2864 }
3013 2865
3014 MainWindow::FileOpenStatus 2866 MainWindow::FileOpenStatus
3015 MainWindow::openAudioFile(QString path, QString location, AudioFileOpenMode mode) 2867 MainWindow::open(RemoteFile source, AudioFileOpenMode mode)
3016 { 2868 {
3017 if (!(QFileInfo(path).exists() && 2869 FileOpenStatus status;
3018 QFileInfo(path).isFile() && 2870
3019 QFileInfo(path).isReadable())) { 2871 if (!source.isAvailable()) return FileOpenFailed;
2872 source.waitForData();
2873
2874 bool canImportLayer = (getMainModel() != 0 &&
2875 m_paneStack != 0 &&
2876 m_paneStack->getCurrentPane() != 0);
2877
2878 if ((status = openAudio(source, mode)) != FileOpenFailed) {
2879 return status;
2880 } else if ((status = openSession(source)) != FileOpenFailed) {
2881 return status;
2882 } else if ((status = openPlaylist(source, mode)) != FileOpenFailed) {
2883 return status;
2884 } else if (!canImportLayer) {
2885 return FileOpenWrongMode;
2886 } else if ((status = openImage(source)) != FileOpenFailed) {
2887 return status;
2888 } else if ((status = openLayer(source)) != FileOpenFailed) {
2889 return status;
2890 } else {
3020 return FileOpenFailed; 2891 return FileOpenFailed;
3021 } 2892 }
2893 }
2894
2895 MainWindow::FileOpenStatus
2896 MainWindow::openAudio(RemoteFile source, AudioFileOpenMode mode)
2897 {
2898 std::cerr << "MainWindow::openAudio(" << source.getLocation().toStdString() << ")" << std::endl;
2899
2900 if (!source.isAvailable()) return FileOpenFailed;
2901 source.waitForData();
3022 2902
3023 m_openingAudioFile = true; 2903 m_openingAudioFile = true;
3024 2904
3025 size_t rate = 0; 2905 size_t rate = 0;
3026 2906
3027 if (Preferences::getInstance()->getResampleOnLoad()) { 2907 if (Preferences::getInstance()->getResampleOnLoad()) {
3028 rate = m_playSource->getSourceSampleRate(); 2908 rate = m_playSource->getSourceSampleRate();
3029 } 2909 }
3030 2910
3031 WaveFileModel *newModel = new WaveFileModel(path, location, rate); 2911 WaveFileModel *newModel = new WaveFileModel(source, rate);
3032 2912
3033 if (!newModel->isOK()) { 2913 if (!newModel->isOK()) {
3034 delete newModel; 2914 delete newModel;
3035 m_openingAudioFile = false; 2915 m_openingAudioFile = false;
3036 return FileOpenFailed; 2916 return FileOpenFailed;
3037 } 2917 }
3038 2918
3039 bool realFile = (location == path);
3040
3041 std::cerr << "mode = " << mode << std::endl; 2919 std::cerr << "mode = " << mode << std::endl;
3042 2920
3043 if (mode == AskUser) { 2921 if (mode == AskUser) {
3044 if (getMainModel()) { 2922 if (getMainModel()) {
3045
3046 std::cerr << "ask user, have main model" << std::endl;
3047 2923
3048 static bool prevSetAsMain = true; 2924 static bool prevSetAsMain = true;
3049 bool setAsMain = true; 2925 bool setAsMain = true;
3050 2926
3051 QStringList items; 2927 QStringList items;
3075 } 2951 }
3076 } 2952 }
3077 2953
3078 if (mode == ReplaceCurrentPane) { 2954 if (mode == ReplaceCurrentPane) {
3079 2955
3080 // std::cerr << "replace current pane" << std::endl;
3081
3082 Pane *pane = m_paneStack->getCurrentPane(); 2956 Pane *pane = m_paneStack->getCurrentPane();
3083 if (pane) { 2957 if (pane) {
3084 // std::cerr << "have pane" << std::endl;
3085
3086 if (getMainModel()) { 2958 if (getMainModel()) {
3087 // std::cerr << "have main model" << std::endl;
3088
3089 View::ModelSet models(pane->getModels()); 2959 View::ModelSet models(pane->getModels());
3090 if (models.find(getMainModel()) != models.end()) { 2960 if (models.find(getMainModel()) != models.end()) {
3091 // std::cerr << "main model is in pane, setting to ReplaceMainModel" << std::endl;
3092 mode = ReplaceMainModel; 2961 mode = ReplaceMainModel;
3093 } 2962 }
3094 } else { 2963 } else {
3095 // std::cerr << "no main model, setting to ReplaceMainModel" << std::endl;
3096 mode = ReplaceMainModel; 2964 mode = ReplaceMainModel;
3097 } 2965 }
3098 } else { 2966 } else {
3099 // std::cerr << "no pane, setting to CreateAdditionalModel" << std::endl;
3100 mode = CreateAdditionalModel; 2967 mode = CreateAdditionalModel;
3101 } 2968 }
3102 } 2969 }
3103 2970
3104 if (mode == CreateAdditionalModel && !getMainModel()) { 2971 if (mode == CreateAdditionalModel && !getMainModel()) {
3105 // std::cerr << "mode is CreateAdditionalModel and no main model, setting to ReplaceMainModel" << std::endl;
3106 mode = ReplaceMainModel; 2972 mode = ReplaceMainModel;
3107 } 2973 }
3108
3109 // std::cerr << "mode now " << mode << std::endl;
3110 2974
3111 if (mode == ReplaceMainModel) { 2975 if (mode == ReplaceMainModel) {
3112 2976
3113 Model *prevMain = getMainModel(); 2977 Model *prevMain = getMainModel();
3114 if (prevMain) { 2978 if (prevMain) {
3120 m_document->setMainModel(newModel); 2984 m_document->setMainModel(newModel);
3121 setupMenus(); 2985 setupMenus();
3122 2986
3123 if (m_sessionFile == "") { 2987 if (m_sessionFile == "") {
3124 setWindowTitle(tr("Sonic Visualiser: %1") 2988 setWindowTitle(tr("Sonic Visualiser: %1")
3125 .arg(QFileInfo(location).fileName())); 2989 .arg(source.getLocation()));
3126 CommandHistory::getInstance()->clear(); 2990 CommandHistory::getInstance()->clear();
3127 CommandHistory::getInstance()->documentSaved(); 2991 CommandHistory::getInstance()->documentSaved();
3128 m_documentModified = false; 2992 m_documentModified = false;
3129 } else { 2993 } else {
3130 setWindowTitle(tr("Sonic Visualiser: %1 [%2]") 2994 setWindowTitle(tr("Sonic Visualiser: %1 [%2]")
3131 .arg(QFileInfo(m_sessionFile).fileName()) 2995 .arg(QFileInfo(m_sessionFile).fileName())
3132 .arg(QFileInfo(location).fileName())); 2996 .arg(source.getLocation()));
3133 if (m_documentModified) { 2997 if (m_documentModified) {
3134 m_documentModified = false; 2998 m_documentModified = false;
3135 documentModified(); // so as to restore "(modified)" window title 2999 documentModified(); // so as to restore "(modified)" window title
3136 } 3000 }
3137 } 3001 }
3138 3002
3139 if (realFile) m_audioFile = path; 3003 if (!source.isRemote()) m_audioFile = source.getLocalFilename();
3140 3004
3141 } else if (mode == CreateAdditionalModel) { 3005 } else if (mode == CreateAdditionalModel) {
3142 3006
3143 CommandHistory::getInstance()->startCompoundOperation 3007 CommandHistory::getInstance()->startCompoundOperation
3144 (tr("Import \"%1\"").arg(QFileInfo(location).fileName()), true); 3008 (tr("Import \"%1\"").arg(source.getLocation()), true);
3145 3009
3146 m_document->addImportedModel(newModel); 3010 m_document->addImportedModel(newModel);
3147 3011
3148 AddPaneCommand *command = new AddPaneCommand(this); 3012 AddPaneCommand *command = new AddPaneCommand(this);
3149 CommandHistory::getInstance()->addCommand(command); 3013 CommandHistory::getInstance()->addCommand(command);
3183 break; 3047 break;
3184 } 3048 }
3185 } 3049 }
3186 3050
3187 CommandHistory::getInstance()->startCompoundOperation 3051 CommandHistory::getInstance()->startCompoundOperation
3188 (tr("Import \"%1\"").arg(QFileInfo(location).fileName()), true); 3052 (tr("Import \"%1\"").arg(source.getLocation()), true);
3189 3053
3190 m_document->addImportedModel(newModel); 3054 m_document->addImportedModel(newModel);
3191 3055
3192 if (replace) { 3056 if (replace) {
3193 m_document->removeLayerFromView(pane, replace); 3057 m_document->removeLayerFromView(pane, replace);
3201 3065
3202 CommandHistory::getInstance()->endCompoundOperation(); 3066 CommandHistory::getInstance()->endCompoundOperation();
3203 } 3067 }
3204 3068
3205 updateMenuStates(); 3069 updateMenuStates();
3206 m_recentFiles.addFile(location); 3070 m_recentFiles.addFile(source.getLocation());
3207 if (realFile) { 3071 if (!source.isRemote()) {
3208 registerLastOpenedFilePath(FileFinder::AudioFile, path); // for file dialog 3072 // for file dialog
3073 registerLastOpenedFilePath(FileFinder::AudioFile,
3074 source.getLocalFilename());
3209 } 3075 }
3210 m_openingAudioFile = false; 3076 m_openingAudioFile = false;
3211 3077
3212 currentPaneChanged(m_paneStack->getCurrentPane()); 3078 currentPaneChanged(m_paneStack->getCurrentPane());
3213 3079
3214 return FileOpenSucceeded; 3080 return FileOpenSucceeded;
3215 } 3081 }
3216 3082
3217 MainWindow::FileOpenStatus 3083 MainWindow::FileOpenStatus
3218 MainWindow::openPlaylistFile(QString path, AudioFileOpenMode mode) 3084 MainWindow::openPlaylist(RemoteFile source, AudioFileOpenMode mode)
3219 { 3085 {
3220 return openPlaylistFile(path, path, mode);
3221 }
3222
3223 MainWindow::FileOpenStatus
3224 MainWindow::openPlaylistFile(QString path, QString location, AudioFileOpenMode mode)
3225 {
3226 if (!(QFileInfo(path).exists() &&
3227 QFileInfo(path).isFile() &&
3228 QFileInfo(path).isReadable())) {
3229 return FileOpenFailed;
3230 }
3231
3232 std::set<QString> extensions; 3086 std::set<QString> extensions;
3233 PlaylistFileReader::getSupportedExtensions(extensions); 3087 PlaylistFileReader::getSupportedExtensions(extensions);
3234 QString extension = QFileInfo(path).suffix(); 3088 QString extension = source.getExtension();
3235 if (extensions.find(extension) == extensions.end()) return FileOpenFailed; 3089 if (extensions.find(extension) == extensions.end()) return FileOpenFailed;
3236 3090
3237 PlaylistFileReader reader(path); 3091 if (!source.isAvailable()) return FileOpenFailed;
3092 source.waitForData();
3093
3094 PlaylistFileReader reader(source.getLocalFilename());
3238 if (!reader.isOK()) return FileOpenFailed; 3095 if (!reader.isOK()) return FileOpenFailed;
3239 3096
3240 PlaylistFileReader::Playlist playlist = reader.load(); 3097 PlaylistFileReader::Playlist playlist = reader.load();
3241 3098
3242 bool someSuccess = false; 3099 bool someSuccess = false;
3243 3100
3244 for (PlaylistFileReader::Playlist::const_iterator i = playlist.begin(); 3101 for (PlaylistFileReader::Playlist::const_iterator i = playlist.begin();
3245 i != playlist.end(); ++i) { 3102 i != playlist.end(); ++i) {
3246 3103
3247 FileOpenStatus status = openURL(*i, mode); 3104 FileOpenStatus status = openAudio(*i, mode);
3248 3105
3249 if (status == FileOpenCancelled) { 3106 if (status == FileOpenCancelled) {
3250 return FileOpenCancelled; 3107 return FileOpenCancelled;
3251 } 3108 }
3252 3109
3256 } 3113 }
3257 } 3114 }
3258 3115
3259 if (someSuccess) return FileOpenSucceeded; 3116 if (someSuccess) return FileOpenSucceeded;
3260 else return FileOpenFailed; 3117 else return FileOpenFailed;
3118 }
3119
3120 MainWindow::FileOpenStatus
3121 MainWindow::openLayer(RemoteFile source)
3122 {
3123 Pane *pane = m_paneStack->getCurrentPane();
3124
3125 if (!pane) {
3126 // shouldn't happen, as the menu action should have been disabled
3127 std::cerr << "WARNING: MainWindow::openLayer: no current pane" << std::endl;
3128 return FileOpenWrongMode;
3129 }
3130
3131 if (!getMainModel()) {
3132 // shouldn't happen, as the menu action should have been disabled
3133 std::cerr << "WARNING: MainWindow::openLayer: No main model -- hence no default sample rate available" << std::endl;
3134 return FileOpenWrongMode;
3135 }
3136
3137 if (!source.isAvailable()) return FileOpenFailed;
3138 source.waitForData();
3139
3140 QString path = source.getLocalFilename();
3141
3142 if (source.getExtension() == "svl" || source.getExtension() == "xml") {
3143
3144 PaneCallback callback(this);
3145 QFile file(path);
3146
3147 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
3148 std::cerr << "ERROR: MainWindow::openLayer("
3149 << source.getLocation().toStdString()
3150 << "): Failed to open file for reading" << std::endl;
3151 return FileOpenFailed;
3152 }
3153
3154 SVFileReader reader(m_document, callback, source.getLocation());
3155 reader.setCurrentPane(pane);
3156
3157 QXmlInputSource inputSource(&file);
3158 reader.parse(inputSource);
3159
3160 if (!reader.isOK()) {
3161 std::cerr << "ERROR: MainWindow::openLayer("
3162 << source.getLocation().toStdString()
3163 << "): Failed to read XML file: "
3164 << reader.getErrorString().toStdString() << std::endl;
3165 return FileOpenFailed;
3166 }
3167
3168 m_recentFiles.addFile(source.getLocation());
3169
3170 if (!source.isRemote()) {
3171 registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog
3172 }
3173
3174 } else {
3175
3176 try {
3177
3178 Model *model = DataFileReaderFactory::load
3179 (path, getMainModel()->getSampleRate());
3180
3181 if (model) {
3182
3183 Layer *newLayer = m_document->createImportedLayer(model);
3184
3185 if (newLayer) {
3186
3187 m_document->addLayerToView(pane, newLayer);
3188 m_recentFiles.addFile(source.getLocation());
3189
3190 if (!source.isRemote()) {
3191 registerLastOpenedFilePath
3192 (FileFinder::LayerFile,
3193 path); // for file dialog
3194 }
3195
3196 return FileOpenSucceeded;
3197 }
3198 }
3199 } catch (DataFileReaderFactory::Exception e) {
3200 if (e == DataFileReaderFactory::ImportCancelled) {
3201 return FileOpenCancelled;
3202 }
3203 }
3204 }
3205
3206 source.setLeaveLocalFile(true);
3207 return FileOpenFailed;
3208 }
3209
3210 MainWindow::FileOpenStatus
3211 MainWindow::openImage(RemoteFile source)
3212 {
3213 Pane *pane = m_paneStack->getCurrentPane();
3214
3215 if (!pane) {
3216 // shouldn't happen, as the menu action should have been disabled
3217 std::cerr << "WARNING: MainWindow::openImage: no current pane" << std::endl;
3218 return FileOpenWrongMode;
3219 }
3220
3221 if (!m_document->getMainModel()) {
3222 return FileOpenWrongMode;
3223 }
3224
3225 bool newLayer = false;
3226
3227 ImageLayer *il = dynamic_cast<ImageLayer *>(pane->getSelectedLayer());
3228 if (!il) {
3229 for (int i = pane->getLayerCount()-1; i >= 0; --i) {
3230 il = dynamic_cast<ImageLayer *>(pane->getLayer(i));
3231 if (il) break;
3232 }
3233 }
3234 if (!il) {
3235 il = dynamic_cast<ImageLayer *>
3236 (m_document->createEmptyLayer(LayerFactory::Image));
3237 if (!il) return FileOpenFailed;
3238 newLayer = true;
3239 }
3240
3241 // We don't put the image file in Recent Files
3242
3243 std::cerr << "openImage: trying location \"" << source.getLocation().toStdString() << "\" in image layer" << std::endl;
3244
3245 if (!il->addImage(m_viewManager->getGlobalCentreFrame(), source.getLocation())) {
3246 if (newLayer) {
3247 m_document->setModel(il, 0); // releasing its model
3248 delete il;
3249 }
3250 return FileOpenFailed;
3251 } else {
3252 if (newLayer) {
3253 m_document->addLayerToView(pane, il);
3254 }
3255 m_paneStack->setCurrentLayer(pane, il);
3256 }
3257
3258 return FileOpenSucceeded;
3259 }
3260
3261 MainWindow::FileOpenStatus
3262 MainWindow::openSession(RemoteFile source)
3263 {
3264 if (!source.isAvailable()) return FileOpenFailed;
3265 if (source.getExtension() != "sv") return FileOpenFailed;
3266 source.waitForData();
3267
3268 BZipFileDevice bzFile(source.getLocalFilename());
3269 if (!bzFile.open(QIODevice::ReadOnly)) return FileOpenFailed;
3270
3271 if (!checkSaveModified()) return FileOpenCancelled;
3272
3273 QString error;
3274 closeSession();
3275 createDocument();
3276
3277 PaneCallback callback(this);
3278 m_viewManager->clearSelections();
3279
3280 SVFileReader reader(m_document, callback, source.getLocation());
3281 QXmlInputSource inputSource(&bzFile);
3282 reader.parse(inputSource);
3283
3284 if (!reader.isOK()) {
3285 error = tr("SV XML file read error:\n%1").arg(reader.getErrorString());
3286 }
3287
3288 bzFile.close();
3289
3290 bool ok = (error == "");
3291
3292 if (ok) {
3293
3294 setWindowTitle(tr("Sonic Visualiser: %1")
3295 .arg(source.getLocation()));
3296
3297 if (!source.isRemote()) m_sessionFile = source.getLocalFilename();
3298
3299 setupMenus();
3300 CommandHistory::getInstance()->clear();
3301 CommandHistory::getInstance()->documentSaved();
3302 m_documentModified = false;
3303 updateMenuStates();
3304
3305 m_recentFiles.addFile(source.getLocation());
3306
3307 if (!source.isRemote()) {
3308 // for file dialog
3309 registerLastOpenedFilePath(FileFinder::SessionFile,
3310 source.getLocalFilename());
3311 }
3312
3313 } else {
3314 setWindowTitle(tr("Sonic Visualiser"));
3315 }
3316
3317 return ok ? FileOpenSucceeded : FileOpenFailed;
3261 } 3318 }
3262 3319
3263 void 3320 void
3264 MainWindow::createPlayTarget() 3321 MainWindow::createPlayTarget()
3265 { 3322 {
3404 3461
3405 QString path = getOpenFileName(FileFinder::SessionFile); 3462 QString path = getOpenFileName(FileFinder::SessionFile);
3406 3463
3407 if (path.isEmpty()) return; 3464 if (path.isEmpty()) return;
3408 3465
3409 if (openSessionFile(path) == FileOpenFailed) { 3466 if (openSession(path) == FileOpenFailed) {
3410 QMessageBox::critical(this, tr("Failed to open file"), 3467 QMessageBox::critical(this, tr("Failed to open file"),
3411 tr("<b>File open failed</b><p>Session file \"%1\" could not be opened").arg(path)); 3468 tr("<b>File open failed</b><p>Session file \"%1\" could not be opened").arg(path));
3412 } 3469 }
3413 } 3470 }
3414 3471
3421 3478
3422 QString path = getOpenFileName(FileFinder::AnyFile); 3479 QString path = getOpenFileName(FileFinder::AnyFile);
3423 3480
3424 if (path.isEmpty()) return; 3481 if (path.isEmpty()) return;
3425 3482
3426 FileOpenStatus status = openSomeFile(path, AskUser); 3483 FileOpenStatus status = open(path, AskUser);
3427 3484
3428 if (status == FileOpenFailed) { 3485 if (status == FileOpenFailed) {
3429 QMessageBox::critical(this, tr("Failed to open file"), 3486 QMessageBox::critical(this, tr("Failed to open file"),
3430 tr("<b>File open failed</b><p>File \"%1\" could not be opened").arg(path)); 3487 tr("<b>File open failed</b><p>File \"%1\" could not be opened").arg(path));
3431 } else if (status == FileOpenWrongMode) { 3488 } else if (status == FileOpenWrongMode) {
3451 3508
3452 settings.setValue("lastremote", text); 3509 settings.setValue("lastremote", text);
3453 3510
3454 if (text.isEmpty()) return; 3511 if (text.isEmpty()) return;
3455 3512
3456 FileOpenStatus status = openURL(QUrl(text)); 3513 FileOpenStatus status = open(text);
3457 3514
3458 if (status == FileOpenFailed) { 3515 if (status == FileOpenFailed) {
3459 QMessageBox::critical(this, tr("Failed to open location"), 3516 QMessageBox::critical(this, tr("Failed to open location"),
3460 tr("<b>Open failed</b><p>URL \"%1\" could not be opened").arg(text)); 3517 tr("<b>Open failed</b><p>URL \"%1\" could not be opened").arg(text));
3461 } else if (status == FileOpenWrongMode) { 3518 } else if (status == FileOpenWrongMode) {
3477 } 3534 }
3478 3535
3479 QString path = action->text(); 3536 QString path = action->text();
3480 if (path == "") return; 3537 if (path == "") return;
3481 3538
3482 FileOpenStatus status = openURL(path); 3539 FileOpenStatus status = open(path);
3483 3540
3484 if (status == FileOpenFailed) { 3541 if (status == FileOpenFailed) {
3485 QMessageBox::critical(this, tr("Failed to open location"), 3542 QMessageBox::critical(this, tr("Failed to open location"),
3486 tr("<b>Open failed</b><p>File or URL \"%1\" could not be opened").arg(path)); 3543 tr("<b>Open failed</b><p>File or URL \"%1\" could not be opened").arg(path));
3487 } else if (status == FileOpenWrongMode) { 3544 } else if (status == FileOpenWrongMode) {
3488 QMessageBox::critical(this, tr("Failed to open location"), 3545 QMessageBox::critical(this, tr("Failed to open location"),
3489 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data")); 3546 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
3490 } 3547 }
3491 } 3548 }
3492 3549
3493 MainWindow::FileOpenStatus
3494 MainWindow::openURL(QUrl url, AudioFileOpenMode mode)
3495 {
3496 if (url.scheme().toLower() == "file" || url.scheme() == "") {
3497
3498 return openSomeFile(url.toLocalFile(), mode);
3499
3500 } else if (!RemoteFile::canHandleScheme(url)) {
3501
3502 QMessageBox::critical(this, tr("Unsupported scheme in URL"),
3503 tr("<b>Download failed</b><p>The URL scheme \"%1\" is not supported")
3504 .arg(url.scheme()));
3505 return FileOpenFailed;
3506
3507 } else {
3508 RemoteFile rf(url);
3509 rf.wait();
3510 if (!rf.isOK()) {
3511 QMessageBox::critical(this, tr("File download failed"),
3512 tr("<b>Download failed</b><p>Failed to download URL \"%1\": %2")
3513 .arg(url.toString()).arg(rf.getErrorString()));
3514 return FileOpenFailed;
3515 }
3516 FileOpenStatus status;
3517 if ((status = openSomeFile(rf.getLocalFilename(), url.toString(),
3518 mode)) !=
3519 FileOpenSucceeded) {
3520 rf.deleteLocalFile();
3521 }
3522 return status;
3523 }
3524 }
3525
3526 MainWindow::FileOpenStatus
3527 MainWindow::openURL(QString ustr, AudioFileOpenMode mode)
3528 {
3529 // This function is used when we don't know whether the string is
3530 // an encoded or human-readable url
3531
3532 QUrl url(ustr);
3533
3534 if (url.scheme().toLower() == "file" || url.scheme() == "") {
3535
3536 FileOpenStatus status = openSomeFile(url.toLocalFile(), mode);
3537 if (status == FileOpenFailed) {
3538 url.setEncodedUrl(ustr.toAscii());
3539 status = openSomeFile(url.toLocalFile(), mode);
3540 }
3541 return status;
3542
3543 } else if (!RemoteFile::canHandleScheme(url)) {
3544
3545 QMessageBox::critical(this, tr("Unsupported scheme in URL"),
3546 tr("<b>Download failed</b><p>The URL scheme \"%1\" is not supported")
3547 .arg(url.scheme()));
3548 return FileOpenFailed;
3549
3550 } else {
3551 RemoteFile rf(url);
3552 rf.wait();
3553 if (!rf.isOK()) {
3554 // rf was created on the assumption that ustr was
3555 // human-readable. Let's try again, this time assuming it
3556 // was already encoded.
3557 std::cerr << "MainWindow::openURL: Failed to retrieve URL \""
3558 << ustr.toStdString() << "\" as human-readable URL; "
3559 << "trying again treating it as encoded URL"
3560 << std::endl;
3561 url.setEncodedUrl(ustr.toAscii());
3562 return openURL(url, mode);
3563 }
3564
3565 FileOpenStatus status;
3566 if ((status = openSomeFile(rf.getLocalFilename(), ustr, mode)) !=
3567 FileOpenSucceeded) {
3568 rf.deleteLocalFile();
3569 }
3570 return status;
3571 }
3572 }
3573
3574 MainWindow::FileOpenStatus
3575 MainWindow::openSomeFile(QString path, AudioFileOpenMode mode)
3576 {
3577 return openSomeFile(path, path, mode);
3578 }
3579
3580 MainWindow::FileOpenStatus
3581 MainWindow::openSomeFile(QString path, QString location,
3582 AudioFileOpenMode mode)
3583 {
3584 FileOpenStatus status;
3585
3586 bool canImportLayer = (getMainModel() != 0 &&
3587 m_paneStack != 0 &&
3588 m_paneStack->getCurrentPane() != 0);
3589
3590 if ((status = openPlaylistFile(path, location, mode)) != FileOpenFailed) {
3591 return status;
3592 } else if ((status = openAudioFile(path, location, mode)) != FileOpenFailed) {
3593 return status;
3594 } else if (QFileInfo(path).suffix().toLower() == "sv" &&
3595 (status = openSessionFile(path, location)) != FileOpenFailed) {
3596 return status;
3597 } else if (!canImportLayer) {
3598 return FileOpenWrongMode;
3599 } else if ((status = openImageFile(path, location)) != FileOpenFailed) {
3600 return status;
3601 } else if ((status = openLayerFile(path, location)) != FileOpenFailed) {
3602 return status;
3603 } else {
3604 return FileOpenFailed;
3605 }
3606 }
3607
3608 MainWindow::FileOpenStatus
3609 MainWindow::openSessionFile(QString path)
3610 {
3611 return openSessionFile(path, path);
3612 }
3613
3614 MainWindow::FileOpenStatus
3615 MainWindow::openSessionFile(QString path, QString location)
3616 {
3617 BZipFileDevice bzFile(path);
3618 if (!bzFile.open(QIODevice::ReadOnly)) {
3619 std::cerr << "Failed to open session file \"" << location.toStdString()
3620 << "\": " << bzFile.errorString().toStdString() << std::endl;
3621 return FileOpenFailed;
3622 }
3623
3624 if (!checkSaveModified()) return FileOpenCancelled;
3625
3626 QString error;
3627 closeSession();
3628 createDocument();
3629
3630 PaneCallback callback(this);
3631 m_viewManager->clearSelections();
3632
3633 SVFileReader reader(m_document, callback, location);
3634 QXmlInputSource inputSource(&bzFile);
3635 reader.parse(inputSource);
3636
3637 if (!reader.isOK()) {
3638 error = tr("SV XML file read error:\n%1").arg(reader.getErrorString());
3639 }
3640
3641 bzFile.close();
3642
3643 bool ok = (error == "");
3644
3645 bool realFile = (location == path);
3646
3647 if (ok) {
3648
3649 setWindowTitle(tr("Sonic Visualiser: %1")
3650 .arg(QFileInfo(location).fileName()));
3651
3652 if (realFile) m_sessionFile = path;
3653
3654 setupMenus();
3655 CommandHistory::getInstance()->clear();
3656 CommandHistory::getInstance()->documentSaved();
3657 m_documentModified = false;
3658 updateMenuStates();
3659
3660 m_recentFiles.addFile(location);
3661
3662 if (realFile) {
3663 registerLastOpenedFilePath(FileFinder::SessionFile, path); // for file dialog
3664 }
3665
3666 } else {
3667 setWindowTitle(tr("Sonic Visualiser"));
3668 }
3669
3670 return ok ? FileOpenSucceeded : FileOpenFailed;
3671 }
3672
3673 void 3550 void
3674 MainWindow::paneDropAccepted(Pane *pane, QStringList uriList) 3551 MainWindow::paneDropAccepted(Pane *pane, QStringList uriList)
3675 { 3552 {
3676 if (pane) m_paneStack->setCurrentPane(pane); 3553 if (pane) m_paneStack->setCurrentPane(pane);
3677 3554
3678 for (QStringList::iterator i = uriList.begin(); i != uriList.end(); ++i) { 3555 for (QStringList::iterator i = uriList.begin(); i != uriList.end(); ++i) {
3679 3556
3680 FileOpenStatus status = openURL(*i, ReplaceCurrentPane); 3557 FileOpenStatus status = open(*i, ReplaceCurrentPane);
3681 3558
3682 if (status == FileOpenFailed) { 3559 if (status == FileOpenFailed) {
3683 QMessageBox::critical(this, tr("Failed to open dropped URL"), 3560 QMessageBox::critical(this, tr("Failed to open dropped URL"),
3684 tr("<b>Open failed</b><p>Dropped URL \"%1\" could not be opened").arg(*i)); 3561 tr("<b>Open failed</b><p>Dropped URL \"%1\" could not be opened").arg(*i));
3685 } else if (status == FileOpenWrongMode) { 3562 } else if (status == FileOpenWrongMode) {
5055 if (message.getMethod() == "open") { 4932 if (message.getMethod() == "open") {
5056 4933
5057 if (message.getArgCount() == 1 && 4934 if (message.getArgCount() == 1 &&
5058 message.getArg(0).canConvert(QVariant::String)) { 4935 message.getArg(0).canConvert(QVariant::String)) {
5059 QString path = message.getArg(0).toString(); 4936 QString path = message.getArg(0).toString();
5060 if (openSomeFile(path, ReplaceMainModel) != FileOpenSucceeded) { 4937 if (open(path, ReplaceMainModel) != FileOpenSucceeded) {
5061 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \"" 4938 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \""
5062 << path.toStdString() << "\"" << std::endl; 4939 << path.toStdString() << "\"" << std::endl;
5063 } 4940 }
5064 //!!! we really need to spin here and not return until the 4941 //!!! we really need to spin here and not return until the
5065 // file has been completely decoded... 4942 // file has been completely decoded...
5068 } else if (message.getMethod() == "openadditional") { 4945 } else if (message.getMethod() == "openadditional") {
5069 4946
5070 if (message.getArgCount() == 1 && 4947 if (message.getArgCount() == 1 &&
5071 message.getArg(0).canConvert(QVariant::String)) { 4948 message.getArg(0).canConvert(QVariant::String)) {
5072 QString path = message.getArg(0).toString(); 4949 QString path = message.getArg(0).toString();
5073 if (openSomeFile(path, CreateAdditionalModel) != FileOpenSucceeded) { 4950 if (open(path, CreateAdditionalModel) != FileOpenSucceeded) {
5074 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \"" 4951 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \""
5075 << path.toStdString() << "\"" << std::endl; 4952 << path.toStdString() << "\"" << std::endl;
5076 } 4953 }
5077 } 4954 }
5078 4955
5085 message.getArg(0).canConvert(QVariant::Int)) { 4962 message.getArg(0).canConvert(QVariant::Int)) {
5086 n = message.getArg(0).toInt() - 1; 4963 n = message.getArg(0).toInt() - 1;
5087 } 4964 }
5088 std::vector<QString> recent = m_recentFiles.getRecent(); 4965 std::vector<QString> recent = m_recentFiles.getRecent();
5089 if (n >= 0 && n < int(recent.size())) { 4966 if (n >= 0 && n < int(recent.size())) {
5090 if (openSomeFile(recent[n], ReplaceMainModel) != FileOpenSucceeded) { 4967 if (open(recent[n], ReplaceMainModel) != FileOpenSucceeded) {
5091 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \"" 4968 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \""
5092 << recent[n].toStdString() << "\"" << std::endl; 4969 << recent[n].toStdString() << "\"" << std::endl;
5093 } 4970 }
5094 } 4971 }
5095 4972