| @@ -94,6 +94,7 @@ void MainWindow::createProjectContentCompIfNeeded() | |||
| { | |||
| clearContentComponent(); | |||
| setContentOwned (JucerApplication::getApp()->createProjectContentComponent(), false); | |||
| jassert (getProjectContentComponent() != nullptr); | |||
| } | |||
| } | |||
| @@ -126,13 +127,17 @@ bool MainWindow::closeProject (Project* project) | |||
| getAppProperties().setValue (getProjectWindowPosName(), getWindowStateAsString()); | |||
| if (! JucerApplication::getApp()->openDocumentManager.closeAllDocumentsUsingProject (*project, true)) | |||
| return false; | |||
| ProjectContentComponent* const pcc = getProjectContentComponent(); | |||
| if (pcc != nullptr) | |||
| { | |||
| pcc->saveTreeViewState(); | |||
| pcc->saveOpenDocumentList(); | |||
| pcc->hideEditor(); | |||
| } | |||
| if (! JucerApplication::getApp()->openDocumentManager.closeAllDocumentsUsingProject (*project, true)) | |||
| return false; | |||
| FileBasedDocument::SaveResult r = project->saveIfNeededAndUserAgrees(); | |||
| @@ -373,6 +378,10 @@ bool MainWindowList::openFile (const File& file) | |||
| w->setProject (newDoc.release()); | |||
| w->makeVisible(); | |||
| avoidSuperimposedWindows (w); | |||
| jassert (w->getProjectContentComponent() != nullptr); | |||
| w->getProjectContentComponent()->reloadLastOpenDocuments(); | |||
| return true; | |||
| } | |||
| } | |||
| @@ -61,6 +61,8 @@ public: | |||
| Component* createEditor() { return new ItemPreviewComponent (file); } | |||
| Component* createViewer() { return createEditor(); } | |||
| void fileHasBeenRenamed (const File& newFile) { file = newFile; } | |||
| String getState() const { return String::empty; } | |||
| void restoreState (const String& state) {} | |||
| String getType() const | |||
| { | |||
| @@ -318,7 +320,7 @@ void RecentDocumentList::clear() | |||
| void RecentDocumentList::newDocumentOpened (OpenDocumentManager::Document* document) | |||
| { | |||
| if (document != getCurrentDocument()) | |||
| if (document != nullptr && document != getCurrentDocument()) | |||
| { | |||
| nextDocs.clear(); | |||
| previousDocs.add (document); | |||
| @@ -371,3 +373,62 @@ void RecentDocumentList::documentAboutToClose (OpenDocumentManager::Document* do | |||
| jassert (! previousDocs.contains (document)); | |||
| jassert (! nextDocs.contains (document)); | |||
| } | |||
| static void restoreDocList (Project& project, Array <OpenDocumentManager::Document*>& list, const XmlElement* xml) | |||
| { | |||
| if (xml != nullptr) | |||
| { | |||
| OpenDocumentManager& odm = JucerApplication::getApp()->openDocumentManager; | |||
| forEachXmlChildElementWithTagName (*xml, e, "DOC") | |||
| { | |||
| const File file (e->getStringAttribute ("file")); | |||
| if (file.exists()) | |||
| { | |||
| OpenDocumentManager::Document* doc = odm.openFile (&project, file); | |||
| if (doc != nullptr) | |||
| { | |||
| doc->restoreState (e->getStringAttribute ("state")); | |||
| list.add (doc); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| void RecentDocumentList::restoreFromXML (Project& project, const XmlElement& xml) | |||
| { | |||
| clear(); | |||
| if (xml.hasTagName ("RECENT_DOCUMENTS")) | |||
| { | |||
| restoreDocList (project, previousDocs, xml.getChildByName ("PREVIOUS")); | |||
| restoreDocList (project, nextDocs, xml.getChildByName ("NEXT")); | |||
| } | |||
| } | |||
| static void saveDocList (const Array <OpenDocumentManager::Document*>& list, XmlElement& xml) | |||
| { | |||
| for (int i = 0; i < list.size(); ++i) | |||
| { | |||
| const OpenDocumentManager::Document& doc = *list.getUnchecked(i); | |||
| XmlElement* e = xml.createNewChildElement ("DOC"); | |||
| e->setAttribute ("file", doc.getFile().getFullPathName()); | |||
| e->setAttribute ("state", doc.getState()); | |||
| } | |||
| } | |||
| XmlElement* RecentDocumentList::createXML() const | |||
| { | |||
| XmlElement* xml = new XmlElement ("RECENT_DOCUMENTS"); | |||
| saveDocList (previousDocs, *xml->createNewChildElement ("PREVIOUS")); | |||
| saveDocList (nextDocs, *xml->createNewChildElement ("NEXT")); | |||
| return xml; | |||
| } | |||
| @@ -60,6 +60,8 @@ public: | |||
| virtual Component* createEditor() = 0; | |||
| virtual Component* createViewer() = 0; | |||
| virtual void fileHasBeenRenamed (const File& newFile) = 0; | |||
| virtual String getState() const = 0; | |||
| virtual void restoreState (const String& state) = 0; | |||
| }; | |||
| //============================================================================== | |||
| @@ -122,6 +124,8 @@ public: | |||
| RecentDocumentList(); | |||
| ~RecentDocumentList(); | |||
| void clear(); | |||
| void newDocumentOpened (OpenDocumentManager::Document* document); | |||
| OpenDocumentManager::Document* getCurrentDocument() const { return previousDocs.getLast(); } | |||
| @@ -134,7 +138,8 @@ public: | |||
| OpenDocumentManager::Document* getClosestPreviousDocOtherThan (OpenDocumentManager::Document* oneToAvoid) const; | |||
| void clear(); | |||
| void restoreFromXML (Project& project, const XmlElement& xml); | |||
| XmlElement* createXML() const; | |||
| private: | |||
| void documentAboutToClose (OpenDocumentManager::Document*); | |||
| @@ -40,7 +40,7 @@ SourceCodeEditor::~SourceCodeEditor() | |||
| SourceCodeDocument* doc = dynamic_cast <SourceCodeDocument*> (getDocument()); | |||
| if (doc != nullptr) | |||
| doc->updateLastPosition (*editor); | |||
| doc->updateLastState (*editor); | |||
| } | |||
| void SourceCodeEditor::createEditor (CodeDocument& codeDocument) | |||
| @@ -97,22 +97,45 @@ void SourceCodeEditor::valueTreeParentChanged (ValueTree&) | |||
| void SourceCodeEditor::valueTreeRedirected (ValueTree&) { updateColourScheme(); } | |||
| //============================================================================== | |||
| SourceCodeDocument::SourceCodeDocument (Project* project_, const File& file_) | |||
| : modDetector (file_), project (project_) | |||
| { | |||
| } | |||
| CodeDocument& SourceCodeDocument::getCodeDocument() | |||
| { | |||
| if (codeDoc == nullptr) | |||
| { | |||
| codeDoc = new CodeDocument(); | |||
| reloadInternal(); | |||
| } | |||
| return *codeDoc; | |||
| } | |||
| Component* SourceCodeDocument::createEditor() | |||
| { | |||
| SourceCodeEditor* e = new SourceCodeEditor (this); | |||
| e->createEditor (codeDoc); | |||
| applyLastPosition (*(e->editor)); | |||
| e->createEditor (getCodeDocument()); | |||
| applyLastState (*(e->editor)); | |||
| return e; | |||
| } | |||
| void SourceCodeDocument::reloadFromFile() | |||
| { | |||
| getCodeDocument(); | |||
| reloadInternal(); | |||
| } | |||
| void SourceCodeDocument::reloadInternal() | |||
| { | |||
| jassert (codeDoc != nullptr); | |||
| modDetector.updateHash(); | |||
| ScopedPointer <InputStream> in (modDetector.getFile().createInputStream()); | |||
| if (in != nullptr) | |||
| codeDoc.loadFromStream (*in); | |||
| codeDoc->loadFromStream (*in); | |||
| } | |||
| bool SourceCodeDocument::save() | |||
| @@ -122,24 +145,24 @@ bool SourceCodeDocument::save() | |||
| { | |||
| FileOutputStream fo (temp.getFile()); | |||
| if (! (fo.openedOk() && codeDoc.writeToStream (fo))) | |||
| if (! (fo.openedOk() && getCodeDocument().writeToStream (fo))) | |||
| return false; | |||
| } | |||
| if (! temp.overwriteTargetFileWithTemporary()) | |||
| return false; | |||
| codeDoc.setSavePoint(); | |||
| getCodeDocument().setSavePoint(); | |||
| modDetector.updateHash(); | |||
| return true; | |||
| } | |||
| void SourceCodeDocument::updateLastPosition (CodeEditorComponent& editor) | |||
| void SourceCodeDocument::updateLastState (CodeEditorComponent& editor) | |||
| { | |||
| lastState = new CodeEditorComponent::State (editor); | |||
| } | |||
| void SourceCodeDocument::applyLastPosition (CodeEditorComponent& editor) const | |||
| void SourceCodeDocument::applyLastState (CodeEditorComponent& editor) const | |||
| { | |||
| if (lastState != nullptr) | |||
| lastState->restoreState (editor); | |||
| @@ -35,31 +35,21 @@ class SourceCodeDocument : public OpenDocumentManager::Document | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| SourceCodeDocument (Project* project_, const File& file_) | |||
| : modDetector (file_), project (project_) | |||
| { | |||
| reloadFromFile(); | |||
| } | |||
| //============================================================================== | |||
| struct Type : public OpenDocumentManager::DocumentType | |||
| { | |||
| bool canOpenFile (const File& file) { return file.hasFileExtension ("cpp;h;hpp;mm;m;c;cc;cxx;txt;inc;tcc;xml;plist;rtf;html;htm;php;py;rb;cs"); } | |||
| Document* openFile (Project* project, const File& file) { return new SourceCodeDocument (project, file); } | |||
| }; | |||
| //============================================================================== | |||
| bool loadedOk() const { return true; } | |||
| bool isForFile (const File& file) const { return getFile() == file; } | |||
| bool isForNode (const ValueTree& node) const { return false; } | |||
| bool refersToProject (Project& p) const { return project == &p; } | |||
| Project* getProject() const { return project; } | |||
| String getName() const { return getFile().getFileName(); } | |||
| String getType() const { return getFile().getFileExtension() + " file"; } | |||
| File getFile() const { return modDetector.getFile(); } | |||
| bool needsSaving() const { return codeDoc.hasChangedSinceSavePoint(); } | |||
| bool hasFileBeenModifiedExternally() { return modDetector.hasBeenModified(); } | |||
| void fileHasBeenRenamed (const File& newFile) { modDetector.fileHasBeenRenamed (newFile); } | |||
| SourceCodeDocument (Project*, const File&); | |||
| bool loadedOk() const { return true; } | |||
| bool isForFile (const File& file) const { return getFile() == file; } | |||
| bool isForNode (const ValueTree& node) const { return false; } | |||
| bool refersToProject (Project& p) const { return project == &p; } | |||
| Project* getProject() const { return project; } | |||
| String getName() const { return getFile().getFileName(); } | |||
| String getType() const { return getFile().getFileExtension() + " file"; } | |||
| File getFile() const { return modDetector.getFile(); } | |||
| bool needsSaving() const { return codeDoc != nullptr && codeDoc->hasChangedSinceSavePoint(); } | |||
| bool hasFileBeenModifiedExternally() { return modDetector.hasBeenModified(); } | |||
| void fileHasBeenRenamed (const File& newFile) { modDetector.fileHasBeenRenamed (newFile); } | |||
| String getState() const { return lastState != nullptr ? lastState->toString() : String::empty; } | |||
| void restoreState (const String& state) { lastState = new CodeEditorComponent::State (state); } | |||
| void reloadFromFile(); | |||
| bool save(); | |||
| @@ -67,15 +57,26 @@ public: | |||
| Component* createEditor(); | |||
| Component* createViewer() { return createEditor(); } | |||
| void updateLastPosition (CodeEditorComponent& editor); | |||
| void applyLastPosition (CodeEditorComponent& editor) const; | |||
| void updateLastState (CodeEditorComponent& editor); | |||
| void applyLastState (CodeEditorComponent& editor) const; | |||
| CodeDocument& getCodeDocument(); | |||
| //============================================================================== | |||
| struct Type : public OpenDocumentManager::DocumentType | |||
| { | |||
| bool canOpenFile (const File& file) { return file.hasFileExtension ("cpp;h;hpp;mm;m;c;cc;cxx;txt;inc;tcc;xml;plist;rtf;html;htm;php;py;rb;cs"); } | |||
| Document* openFile (Project* project, const File& file) { return new SourceCodeDocument (project, file); } | |||
| }; | |||
| protected: | |||
| FileModificationDetector modDetector; | |||
| CodeDocument codeDoc; | |||
| ScopedPointer<CodeDocument> codeDoc; | |||
| Project* project; | |||
| ScopedPointer<CodeEditorComponent::State> lastState; | |||
| void reloadInternal(); | |||
| }; | |||
| //============================================================================== | |||
| @@ -218,6 +218,31 @@ void ProjectContentComponent::saveTreeViewState() | |||
| } | |||
| } | |||
| void ProjectContentComponent::saveOpenDocumentList() | |||
| { | |||
| if (project != nullptr) | |||
| { | |||
| ScopedPointer<XmlElement> xml (recentDocumentList.createXML()); | |||
| if (xml != nullptr) | |||
| getAppProperties().setValue ("lastDocs_" + project->getProjectUID(), xml); | |||
| } | |||
| } | |||
| void ProjectContentComponent::reloadLastOpenDocuments() | |||
| { | |||
| if (project != nullptr) | |||
| { | |||
| ScopedPointer<XmlElement> xml (getAppProperties().getXmlValue ("lastDocs_" + project->getProjectUID())); | |||
| if (xml != nullptr) | |||
| { | |||
| recentDocumentList.restoreFromXML (*project, *xml); | |||
| showDocument (recentDocumentList.getCurrentDocument()); | |||
| } | |||
| } | |||
| } | |||
| void ProjectContentComponent::changeListenerCallback (ChangeBroadcaster*) | |||
| { | |||
| updateMissingFileStatuses(); | |||
| @@ -251,8 +276,11 @@ bool ProjectContentComponent::showDocument (OpenDocumentManager::Document* doc) | |||
| if (doc->hasFileBeenModifiedExternally()) | |||
| doc->reloadFromFile(); | |||
| if (doc == getCurrentDocument()) | |||
| if (doc == getCurrentDocument() && contentView != nullptr) | |||
| { | |||
| contentView->grabKeyboardFocus(); | |||
| return true; | |||
| } | |||
| recentDocumentList.newDocumentOpened (doc); | |||
| @@ -265,7 +293,6 @@ void ProjectContentComponent::hideEditor() | |||
| contentView = nullptr; | |||
| updateMainWindowTitle(); | |||
| commandManager->commandStatusChanged(); | |||
| recentDocumentList.clear(); | |||
| } | |||
| void ProjectContentComponent::hideDocument (OpenDocumentManager::Document* doc) | |||
| @@ -303,7 +330,12 @@ bool ProjectContentComponent::setEditorComponent (Component* editor, OpenDocumen | |||
| bool ProjectContentComponent::goToPreviousFile() | |||
| { | |||
| return showDocument (recentDocumentList.getPrevious()); | |||
| OpenDocumentManager::Document* currentSourceDoc = recentDocumentList.getCurrentDocument(); | |||
| if (currentSourceDoc != nullptr && currentSourceDoc != getCurrentDocument()) | |||
| return showDocument (currentSourceDoc); | |||
| else | |||
| return showDocument (recentDocumentList.getPrevious()); | |||
| } | |||
| bool ProjectContentComponent::goToNextFile() | |||
| @@ -44,7 +44,10 @@ public: | |||
| Project* getProject() const noexcept { return project; } | |||
| virtual void setProject (Project* project); | |||
| void saveTreeViewState(); | |||
| void saveOpenDocumentList(); | |||
| void reloadLastOpenDocuments(); | |||
| bool showEditorForFile (const File& f); | |||
| File getCurrentFile() const; | |||
| @@ -46,6 +46,8 @@ public: | |||
| void itemSelectionChanged (bool isNowSelected); | |||
| void itemDoubleClicked (const MouseEvent&); | |||
| void cancelDelayedSelectionTimer(); | |||
| //============================================================================== | |||
| virtual Font getFont() const; | |||
| virtual String getRenamingName() const = 0; | |||
| @@ -89,7 +91,6 @@ public: | |||
| protected: | |||
| ProjectContentComponent* getProjectContentComponent() const; | |||
| void cancelDelayedSelectionTimer(); | |||
| virtual void addSubItems() {} | |||
| private: | |||
| @@ -128,7 +129,17 @@ public: | |||
| const ScopedPointer<XmlElement> treeOpenness (getAppProperties().getXmlValue (opennessStateKey)); | |||
| if (treeOpenness != nullptr) | |||
| { | |||
| tree.restoreOpennessState (*treeOpenness, true); | |||
| for (int i = tree.getNumSelectedItems(); --i >= 0;) | |||
| { | |||
| JucerTreeViewBase* item = dynamic_cast<JucerTreeViewBase*> (tree.getSelectedItem (i)); | |||
| if (item != nullptr) | |||
| item->cancelDelayedSelectionTimer(); | |||
| } | |||
| } | |||
| } | |||
| void saveOpenness() | |||
| @@ -155,6 +155,9 @@ public: | |||
| /** Represents a combination of all the mouse buttons at once. */ | |||
| allMouseButtonModifiers = leftButtonModifier | rightButtonModifier | middleButtonModifier, | |||
| /** Represents a combination of all the alt, ctrl and command key modifiers. */ | |||
| ctrlAltCommandModifiers = ctrlModifier | altModifier | commandModifier | |||
| }; | |||
| //============================================================================== | |||
| @@ -171,11 +174,11 @@ public: | |||
| /** Returns the raw flags for direct testing. */ | |||
| inline int getRawFlags() const noexcept { return flags; } | |||
| inline const ModifierKeys withoutFlags (int rawFlagsToClear) const noexcept { return ModifierKeys (flags & ~rawFlagsToClear); } | |||
| inline const ModifierKeys withFlags (int rawFlagsToSet) const noexcept { return ModifierKeys (flags | rawFlagsToSet); } | |||
| ModifierKeys withoutFlags (int rawFlagsToClear) const noexcept { return ModifierKeys (flags & ~rawFlagsToClear); } | |||
| ModifierKeys withFlags (int rawFlagsToSet) const noexcept { return ModifierKeys (flags | rawFlagsToSet); } | |||
| /** Tests a combination of flags and returns true if any of them are set. */ | |||
| inline bool testFlags (const int flagsToTest) const noexcept { return (flags & flagsToTest) != 0; } | |||
| bool testFlags (const int flagsToTest) const noexcept { return (flags & flagsToTest) != 0; } | |||
| /** Returns the total number of mouse buttons that are down. */ | |||
| int getNumMouseButtonsDown() const noexcept; | |||
| @@ -761,86 +761,100 @@ void TreeView::scrollToKeepItemVisible (TreeViewItem* item) | |||
| } | |||
| } | |||
| bool TreeView::keyPressed (const KeyPress& key) | |||
| void TreeView::toggleOpenSelectedItem() | |||
| { | |||
| if (key.isKeyCode (KeyPress::upKey)) | |||
| { | |||
| moveSelectedRow (-1); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::downKey)) | |||
| { | |||
| moveSelectedRow (1); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::pageDownKey) || key.isKeyCode (KeyPress::pageUpKey)) | |||
| TreeViewItem* const firstSelected = getSelectedItem (0); | |||
| if (firstSelected != nullptr) | |||
| firstSelected->setOpen (! firstSelected->isOpen()); | |||
| } | |||
| void TreeView::moveOutOfSelectedItem() | |||
| { | |||
| TreeViewItem* const firstSelected = getSelectedItem (0); | |||
| if (firstSelected != nullptr) | |||
| { | |||
| if (rootItem != nullptr) | |||
| if (firstSelected->isOpen()) | |||
| { | |||
| int rowsOnScreen = getHeight() / jmax (1, rootItem->itemHeight); | |||
| firstSelected->setOpen (false); | |||
| } | |||
| else | |||
| { | |||
| TreeViewItem* parent = firstSelected->parentItem; | |||
| if (key.isKeyCode (KeyPress::pageUpKey)) | |||
| rowsOnScreen = -rowsOnScreen; | |||
| if ((! rootItemVisible) && parent == rootItem) | |||
| parent = nullptr; | |||
| if (rowsOnScreen != 0) | |||
| moveSelectedRow (rowsOnScreen); | |||
| if (parent != nullptr) | |||
| { | |||
| parent->setSelected (true, true); | |||
| scrollToKeepItemVisible (parent); | |||
| } | |||
| } | |||
| } | |||
| else if (key.isKeyCode (KeyPress::homeKey)) | |||
| { | |||
| moveSelectedRow (-0x3fffffff); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::endKey)) | |||
| { | |||
| moveSelectedRow (0x3fffffff); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::returnKey)) | |||
| } | |||
| void TreeView::moveIntoSelectedItem() | |||
| { | |||
| TreeViewItem* const firstSelected = getSelectedItem (0); | |||
| if (firstSelected != nullptr) | |||
| { | |||
| TreeViewItem* const firstSelected = getSelectedItem (0); | |||
| if (firstSelected != nullptr) | |||
| firstSelected->setOpen (! firstSelected->isOpen()); | |||
| if (firstSelected->isOpen() || ! firstSelected->mightContainSubItems()) | |||
| moveSelectedRow (1); | |||
| else | |||
| firstSelected->setOpen (true); | |||
| } | |||
| else if (key.isKeyCode (KeyPress::leftKey)) | |||
| } | |||
| void TreeView::moveByPages (int numPages) | |||
| { | |||
| TreeViewItem* currentItem = getSelectedItem (0); | |||
| if (currentItem != nullptr) | |||
| { | |||
| TreeViewItem* const firstSelected = getSelectedItem (0); | |||
| const Rectangle<int> pos (currentItem->getItemPosition (false)); | |||
| const int targetY = pos.getY() + numPages * (getHeight() - pos.getHeight()); | |||
| int currentRow = currentItem->getRowNumberInTree(); | |||
| if (firstSelected != nullptr) | |||
| for (;;) | |||
| { | |||
| if (firstSelected->isOpen()) | |||
| { | |||
| firstSelected->setOpen (false); | |||
| } | |||
| else | |||
| { | |||
| TreeViewItem* parent = firstSelected->parentItem; | |||
| moveSelectedRow (numPages); | |||
| currentItem = getSelectedItem (0); | |||
| if ((! rootItemVisible) && parent == rootItem) | |||
| parent = nullptr; | |||
| if (currentItem == nullptr) | |||
| break; | |||
| if (parent != nullptr) | |||
| { | |||
| parent->setSelected (true, true); | |||
| scrollToKeepItemVisible (parent); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| else if (key.isKeyCode (KeyPress::rightKey)) | |||
| { | |||
| TreeViewItem* const firstSelected = getSelectedItem (0); | |||
| const int y = currentItem->getItemPosition (false).getY(); | |||
| if ((numPages < 0 && y <= targetY) || (numPages > 0 && y >= targetY)) | |||
| break; | |||
| if (firstSelected != nullptr) | |||
| { | |||
| if (firstSelected->isOpen() || ! firstSelected->mightContainSubItems()) | |||
| moveSelectedRow (1); | |||
| else | |||
| firstSelected->setOpen (true); | |||
| const int newRow = currentItem->getRowNumberInTree(); | |||
| if (newRow == currentRow) | |||
| break; | |||
| currentRow = newRow; | |||
| } | |||
| } | |||
| else | |||
| } | |||
| bool TreeView::keyPressed (const KeyPress& key) | |||
| { | |||
| if (rootItem != nullptr | |||
| && ! key.getModifiers().testFlags (ModifierKeys::ctrlAltCommandModifiers)) | |||
| { | |||
| return false; | |||
| if (key.getKeyCode() == KeyPress::upKey) { moveSelectedRow (-1); return true; } | |||
| if (key.getKeyCode() == KeyPress::downKey) { moveSelectedRow (1); return true; } | |||
| if (key.getKeyCode() == KeyPress::homeKey) { moveSelectedRow (-0x3fffffff); return true; } | |||
| if (key.getKeyCode() == KeyPress::endKey) { moveSelectedRow (0x3fffffff); return true; } | |||
| if (key.getKeyCode() == KeyPress::pageUpKey) { moveByPages (-1); return true; } | |||
| if (key.getKeyCode() == KeyPress::pageDownKey) { moveByPages (1); return true; } | |||
| if (key.getKeyCode() == KeyPress::returnKey) { toggleOpenSelectedItem(); return true; } | |||
| if (key.getKeyCode() == KeyPress::leftKey) { moveOutOfSelectedItem(); return true; } | |||
| if (key.getKeyCode() == KeyPress::rightKey) { moveIntoSelectedItem(); return true; } | |||
| } | |||
| return true; | |||
| return false; | |||
| } | |||
| void TreeView::itemsChanged() noexcept | |||
| @@ -820,6 +820,10 @@ private: | |||
| void hideDragHighlight() noexcept; | |||
| void handleDrag (const StringArray& files, const SourceDetails&); | |||
| void handleDrop (const StringArray& files, const SourceDetails&); | |||
| void toggleOpenSelectedItem(); | |||
| void moveOutOfSelectedItem(); | |||
| void moveIntoSelectedItem(); | |||
| void moveByPages (int numPages); | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeView); | |||
| }; | |||
| @@ -1425,3 +1425,18 @@ void CodeEditorComponent::State::restoreState (CodeEditorComponent& editor) cons | |||
| if (lastTopLine > 0 && lastTopLine < editor.getDocument().getNumLines()) | |||
| editor.scrollToLine (lastTopLine); | |||
| } | |||
| CodeEditorComponent::State::State (const String& s) | |||
| { | |||
| StringArray tokens; | |||
| tokens.addTokens (s, ":", String::empty); | |||
| lastTopLine = tokens[0].getIntValue(); | |||
| lastCaretPos = tokens[1].getIntValue(); | |||
| lastSelectionEnd = tokens[2].getIntValue(); | |||
| } | |||
| String CodeEditorComponent::State::toString() const | |||
| { | |||
| return String (lastTopLine) + ":" + String (lastCaretPos) + ":" + String (lastSelectionEnd); | |||
| } | |||
| @@ -163,11 +163,16 @@ public: | |||
| { | |||
| /** Creates an object containing the state of the given editor. */ | |||
| State (const CodeEditorComponent& editor); | |||
| /** Creates a state object from a string that was previously created with toString(). */ | |||
| State (const String& stringifiedVersion); | |||
| State (const State& other) noexcept; | |||
| /** Updates the given editor with this saved state. */ | |||
| void restoreState (CodeEditorComponent& editor) const; | |||
| /** Returns a stringified version of this state that can be used to recreate it later. */ | |||
| String toString() const; | |||
| private: | |||
| int lastTopLine, lastCaretPos, lastSelectionEnd; | |||
| }; | |||