| @@ -1055,7 +1055,7 @@ bool ProjucerApplication::perform (const InvocationInfo& info) | |||||
| case CommandIDs::newPIP: createNewPIP(); break; | case CommandIDs::newPIP: createNewPIP(); break; | ||||
| case CommandIDs::open: askUserToOpenFile(); break; | case CommandIDs::open: askUserToOpenFile(); break; | ||||
| case CommandIDs::launchDemoRunner: launchDemoRunner(); break; | case CommandIDs::launchDemoRunner: launchDemoRunner(); break; | ||||
| case CommandIDs::saveAll: openDocumentManager.saveAll(); break; | |||||
| case CommandIDs::saveAll: saveAllDocuments(); break; | |||||
| case CommandIDs::closeAllWindows: closeAllMainWindowsAndQuitIfNeeded(); break; | case CommandIDs::closeAllWindows: closeAllMainWindowsAndQuitIfNeeded(); break; | ||||
| case CommandIDs::closeAllDocuments: closeAllDocuments (true); break; | case CommandIDs::closeAllDocuments: closeAllDocuments (true); break; | ||||
| case CommandIDs::clearRecentFiles: clearRecentFiles(); break; | case CommandIDs::clearRecentFiles: clearRecentFiles(); break; | ||||
| @@ -1120,6 +1120,15 @@ bool ProjucerApplication::openFile (const File& file) | |||||
| return mainWindowList.openFile (file); | return mainWindowList.openFile (file); | ||||
| } | } | ||||
| void ProjucerApplication::saveAllDocuments() | |||||
| { | |||||
| openDocumentManager.saveAll(); | |||||
| for (int i = 0; i < mainWindowList.windows.size(); ++i) | |||||
| if (auto* pcc = mainWindowList.windows.getUnchecked(i)->getProjectContentComponent()) | |||||
| pcc->refreshProjectTreeFileStatuses(); | |||||
| } | |||||
| bool ProjucerApplication::closeAllDocuments (bool askUserToSave) | bool ProjucerApplication::closeAllDocuments (bool askUserToSave) | ||||
| { | { | ||||
| return openDocumentManager.closeAll (askUserToSave); | return openDocumentManager.closeAll (askUserToSave); | ||||
| @@ -96,6 +96,7 @@ public: | |||||
| void createNewPIP(); | void createNewPIP(); | ||||
| void askUserToOpenFile(); | void askUserToOpenFile(); | ||||
| bool openFile (const File&); | bool openFile (const File&); | ||||
| void saveAllDocuments(); | |||||
| bool closeAllDocuments (bool askUserToSave); | bool closeAllDocuments (bool askUserToSave); | ||||
| bool closeAllMainWindows(); | bool closeAllMainWindows(); | ||||
| void closeAllMainWindowsAndQuitIfNeeded(); | void closeAllMainWindowsAndQuitIfNeeded(); | ||||
| @@ -47,13 +47,20 @@ bool DocumentEditorComponent::documentAboutToClose (OpenDocumentManager::Documen | |||||
| { | { | ||||
| jassert (document != nullptr); | jassert (document != nullptr); | ||||
| if (ProjectContentComponent* pcc = findParentComponentOfClass<ProjectContentComponent>()) | |||||
| if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>()) | |||||
| pcc->hideDocument (document); | pcc->hideDocument (document); | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| void DocumentEditorComponent::setEditedState (bool /*hasBeenEdited*/) | |||||
| void DocumentEditorComponent::setEditedState (bool hasBeenEdited) | |||||
| { | { | ||||
| if (hasBeenEdited != lastEditedState) | |||||
| { | |||||
| if (auto* pcc = findParentComponentOfClass<ProjectContentComponent>()) | |||||
| pcc->refreshProjectTreeFileStatuses(); | |||||
| lastEditedState = hasBeenEdited; | |||||
| } | |||||
| } | } | ||||
| @@ -43,6 +43,7 @@ public: | |||||
| protected: | protected: | ||||
| OpenDocumentManager::Document* document; | OpenDocumentManager::Document* document; | ||||
| bool lastEditedState = false; | |||||
| void setEditedState (bool hasBeenEdited); | void setEditedState (bool hasBeenEdited); | ||||
| @@ -465,6 +465,21 @@ public: | |||||
| return getFile().getFileName(); | return getFile().getFileName(); | ||||
| } | } | ||||
| void paintItem (Graphics& g, int width, int height) override | |||||
| { | |||||
| JucerTreeViewBase::paintItem (g, width, height); | |||||
| if (item.needsSaving()) | |||||
| { | |||||
| auto bounds = g.getClipBounds().withY (0).withHeight (height); | |||||
| g.setFont (getFont()); | |||||
| g.setColour (getContentColour (false)); | |||||
| g.drawFittedText ("*", bounds.removeFromLeft (height), Justification::centred, 1); | |||||
| } | |||||
| } | |||||
| static File findCorrespondingHeaderOrCpp (const File& f) | static File findCorrespondingHeaderOrCpp (const File& f) | ||||
| { | { | ||||
| if (f.hasFileExtension (sourceFileExtensions)) return f.withFileExtension (".h"); | if (f.hasFileExtension (sourceFileExtensions)) return f.withFileExtension (".h"); | ||||
| @@ -334,6 +334,13 @@ void ProjectContentComponent::changeListenerCallback (ChangeBroadcaster*) | |||||
| updateMissingFileStatuses(); | updateMissingFileStatuses(); | ||||
| } | } | ||||
| void ProjectContentComponent::refreshProjectTreeFileStatuses() | |||||
| { | |||||
| if (auto* projectTab = getProjectTab()) | |||||
| if (auto* fileTree = projectTab->getFileTreePanel()) | |||||
| fileTree->repaint(); | |||||
| } | |||||
| void ProjectContentComponent::updateMissingFileStatuses() | void ProjectContentComponent::updateMissingFileStatuses() | ||||
| { | { | ||||
| if (auto* pTab = getProjectTab()) | if (auto* pTab = getProjectTab()) | ||||
| @@ -482,6 +489,8 @@ void ProjectContentComponent::saveDocument() | |||||
| { | { | ||||
| if (! currentDocument->save()) | if (! currentDocument->save()) | ||||
| showSaveWarning (currentDocument); | showSaveWarning (currentDocument); | ||||
| refreshProjectTreeFileStatuses(); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -491,8 +500,13 @@ void ProjectContentComponent::saveDocument() | |||||
| void ProjectContentComponent::saveAs() | void ProjectContentComponent::saveAs() | ||||
| { | { | ||||
| if (currentDocument != nullptr && ! currentDocument->saveAs()) | |||||
| showSaveWarning (currentDocument); | |||||
| if (currentDocument != nullptr) | |||||
| { | |||||
| if (! currentDocument->saveAs()) | |||||
| showSaveWarning (currentDocument); | |||||
| refreshProjectTreeFileStatuses(); | |||||
| } | |||||
| } | } | ||||
| bool ProjectContentComponent::goToPreviousFile() | bool ProjectContentComponent::goToPreviousFile() | ||||
| @@ -97,6 +97,7 @@ public: | |||||
| void deleteSelectedTreeItems(); | void deleteSelectedTreeItems(); | ||||
| void refreshProjectTreeFileStatuses(); | |||||
| void updateMissingFileStatuses(); | void updateMissingFileStatuses(); | ||||
| void createProjectTabs(); | void createProjectTabs(); | ||||
| void deleteProjectTabs(); | void deleteProjectTabs(); | ||||
| @@ -1574,6 +1574,23 @@ bool Project::Item::isIconCrossedOut() const | |||||
| || getFile().hasFileExtension (headerFileExtensions)); | || getFile().hasFileExtension (headerFileExtensions)); | ||||
| } | } | ||||
| bool Project::Item::needsSaving() const noexcept | |||||
| { | |||||
| auto& odm = ProjucerApplication::getApp().openDocumentManager; | |||||
| if (odm.anyFilesNeedSaving()) | |||||
| { | |||||
| for (int i = 0; i < odm.getNumOpenDocuments(); ++i) | |||||
| { | |||||
| auto* doc = odm.getOpenDocument (i); | |||||
| if (doc->needsSaving() && doc->getFile() == getFile()) | |||||
| return true; | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| ValueTree Project::getConfigNode() | ValueTree Project::getConfigNode() | ||||
| { | { | ||||
| @@ -300,6 +300,8 @@ public: | |||||
| Icon getIcon (bool isOpen = false) const; | Icon getIcon (bool isOpen = false) const; | ||||
| bool isIconCrossedOut() const; | bool isIconCrossedOut() const; | ||||
| bool needsSaving() const noexcept; | |||||
| Project& project; | Project& project; | ||||
| ValueTree state; | ValueTree state; | ||||