@@ -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; | |||
}; | |||