Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added support for grouped changes (transactions)

  • Loading branch information...
commit e328a0cceee33a2d2d6fba83527c11ccacfb9cef 1 parent 575a468
Alexander Stigsen authored
View
46 src/ApiHandler.cpp
@@ -55,6 +55,8 @@ ApiHandler::ApiHandler(eApp& app)
m_ipcEditorFunctions["GetChangesSince"] = &ApiHandler::IpcEditorGetChangesSince;
m_ipcEditorFunctions["ShowInputLine"] = &ApiHandler::IpcEditorShowInputLine;
m_ipcEditorFunctions["WatchChanges"] = &ApiHandler::IpcEditorWatchChanges;
+ m_ipcEditorFunctions["StartChange"] = &ApiHandler::IpcEditorStartChange;
+ m_ipcEditorFunctions["EndChange"] = &ApiHandler::IpcEditorEndChange;
// Start the ipc server
m_ipcThread = new eIpcThread(*this);
@@ -196,6 +198,18 @@ void ApiHandler::OnIpcClosed(wxCommandEvent& event) {
else ++p;
}
+ boost::ptr_map<IConnection*, ConnectionState>::const_iterator c = m_connStates.find(conn);
+ if (c != m_connStates.end()) {
+ // If any editors are still in a change group, we have to release them
+ const set<int>& editorsInChange = c->second->editorsInChange;
+ if (!editorsInChange.empty()) {
+ for (set<int>::const_iterator e = editorsInChange.begin(); e != editorsInChange.end(); ++e) {
+ EditorCtrl* editor = m_app.GetEditorCtrl(*e);
+ if (editor) editor->EndChange();
+ }
+ }
+ }
+
// Clear any associated state
m_connStates.erase(conn);
}
@@ -447,6 +461,7 @@ void ApiHandler::IpcEditorShowInputLine(EditorCtrl& , IConnection& conn) {
// Show input line
EditorFrame* frame = m_app.GetTopFrame();
if (!frame) return;
+
frame->ShowInputPanel(notifier_id, caption);
// Return notifier id
@@ -500,6 +515,37 @@ void ApiHandler::IpcEditorGetChangesSince(EditorCtrl& editor, IConnection& conn)
writer.write_reply(changedlines);
}
+void ApiHandler::IpcEditorStartChange(EditorCtrl& editor, IConnection& conn) {
+ const int editorId = editor.GetId();
+
+ // Only allow one level of change grouping
+ boost::ptr_map<IConnection*,ConnectionState>::iterator p = m_connStates.find(&conn);
+ if (p == m_connStates.end()) {
+ IConnection* c = &conn;
+ m_connStates.insert(c, new ConnectionState);
+ p = m_connStates.find(&conn);
+ }
+ else {
+ const set<int>& editorsInChange = p->second->editorsInChange;
+ if (editorsInChange.find(editorId) != editorsInChange.end()) return;
+ }
+
+ p->second->editorsInChange.insert(editorId);
+ editor.StartChange();
+}
+
+void ApiHandler::IpcEditorEndChange(EditorCtrl& editor, IConnection& conn) {
+ const int editorId = editor.GetId();
+
+ boost::ptr_map<IConnection*,ConnectionState>::iterator p = m_connStates.find(&conn);
+ if (p == m_connStates.end()) return;
+ set<int>& editorsInChange = p->second->editorsInChange;
+ if (editorsInChange.find(editorId) != editorsInChange.end()) return;
+ editorsInChange.erase(editorId);
+
+ editor.EndChange();
+}
+
void ApiHandler::OnInputLineChanged(unsigned int nid, const wxString& text) {
// Look up notifier id
map<unsigned int, IConnection*>::const_iterator p = m_notifiers.find(nid);
View
4 src/ApiHandler.h
@@ -22,6 +22,7 @@
#include <vector>
#include <map>
+#include <set>
#include <boost/ptr_container/ptr_map.hpp>
using namespace std;
@@ -44,6 +45,7 @@ class ApiHandler : public wxEvtHandler {
private:
struct ConnectionState {
vector<doc_id> docHandles;
+ set<int> editorsInChange;
};
// Event handlers
@@ -80,6 +82,8 @@ class ApiHandler : public wxEvtHandler {
void IpcEditorWatchTab(EditorCtrl& editor, IConnection& conn);
void IpcEditorWatchChanges(EditorCtrl& editor, IConnection& conn);
void IpcEditorGetChangesSince(EditorCtrl& editor, IConnection& conn);
+ void IpcEditorStartChange(EditorCtrl& editor, IConnection& conn);
+ void IpcEditorEndChange(EditorCtrl& editor, IConnection& conn);
// Notification Handlers
void OnEditorChanged(unsigned int nid, bool state);
View
64 src/Document.cpp
@@ -26,8 +26,11 @@
Document::Document(const doc_id& di, CatalystWrapper cw):
m_catalyst(cw.m_catalyst),
dispatcher(cw.GetDispatcher()),
- do_notify(true),
m_textData(cw.m_catalyst),
+ in_change(false),
+ change_level(0),
+ do_notify(true),
+ do_notify_top(0),
m_re(NULL),
m_trackChanges(NULL)
{
@@ -41,8 +44,11 @@ Document::Document(CatalystWrapper cw):
m_catalyst(cw.m_catalyst),
dispatcher(cw.GetDispatcher()),
m_docId(DRAFT,-1,-1),
- do_notify(true),
m_textData(cw.m_catalyst),
+ in_change(false),
+ change_level(0),
+ do_notify(true),
+ do_notify_top(0),
m_re(NULL),
m_trackChanges(NULL)
{
@@ -267,19 +273,50 @@ void Document::WriteText(wxOutputStream& stream) const {
m_textData.WriteText(stream);
}
-void Document::StartChange() {
+void Document::StartChange(bool doNotify) {
wxASSERT(IsOk());
- do_notify = false;
+
+ // Always freeze before starting grouped changes
+ if (change_level == 0) {
+ Freeze();
+ in_change = true;
+ }
+
+ // If notification is stopped at any nesting level
+ // no lower level can enable it
+ if (do_notify && !doNotify) {
+ do_notify = false;
+ do_notify_top = change_level;
+ }
+
+ ++change_level;
}
-void Document::EndChange() {
+void Document::EndChange(int forceTo) {
wxASSERT(IsOk());
- do_notify = true;
+ wxASSERT(change_level > 0);
+ wxASSERT(forceTo < change_level);
- // Notify subscribers that the revision has changed
- m_catalyst.UnLock();
- dispatcher.Notify(wxT("DOC_UPDATEREVISION"), &m_docId, 0);
- m_catalyst.ReLock();
+ // Change nesting level
+ if (forceTo == -1) --change_level;
+ else change_level = forceTo;
+
+ // Restore notifications
+ if (change_level <= do_notify_top) {
+ do_notify = true;
+ do_notify_top = 0;
+ }
+
+ // Freeze when the entire change is complete
+ if (change_level == 0) {
+ in_change = false;
+ Freeze();
+
+ // Notify subscribers that the revision has changed
+ m_catalyst.UnLock();
+ dispatcher.Notify(wxT("DOC_UPDATEREVISION"), &m_docId, 0);
+ m_catalyst.ReLock();
+ }
}
wxString Document::GetTextPart(int start_pos, int end_pos) const {
@@ -1825,6 +1862,7 @@ unsigned int Document::Replace(unsigned int start_pos, unsigned int end_pos, con
void Document::Freeze() {
wxASSERT(IsOk());
+ if (in_change) return; // Don't freeze during grouped changes
if (m_docId.IsDocument()) return; // Only a Draft can be frozen
if (vHistory.GetSize() == 0) NewRevision();
@@ -1867,6 +1905,12 @@ void Document::SetDocument(const doc_id& di) {
//wxASSERT(m_catalyst.IsOk(di));
if (m_docId == di) return;
+ // During grouped changes moving away from current
+ // change cleans it up
+ if (in_change && !IsFrozen()) {
+ m_catalyst.DeleteDraft(m_docId);
+ }
+
m_docId = di;
vRevisions = (m_docId.IsDraft()) ? m_catalyst.GetRevView() : m_catalyst.GetDocView();
View
12 src/Document.h
@@ -145,8 +145,10 @@ class Document {
void MakeHead();
// Grouping of multiple changes
- void StartChange();
- void EndChange();
+ void StartChange(bool doNotify=false);
+ void EndChange(int forceTo=-1);
+ bool InChange() const {return in_change;};
+ int GetChangeLevel() const {return change_level;};
bool operator==(const doc_id& di) const;
bool operator!=(const doc_id& di) const;
@@ -167,9 +169,13 @@ class Document {
c4_View vNodes;
c4_View vHistory;
doc_id m_docId;
- bool do_notify;
DataText m_textData;
+ bool in_change;
+ int change_level;
+ bool do_notify;
+ int do_notify_top;
+
// Cache of last compiled regex
mutable wxString m_regex_cache;
mutable int m_options_cache;
View
57 src/EditorCtrl.cpp
@@ -690,53 +690,28 @@ bool EditorCtrl::IsOk() const {
return (size.x == 0 && size.y == 0) || bitmap.Ok();
}
-// WARNING: Be aware that during a change grouping, lines is not valid
-// Only call functions like lines.RemoveAllSelections() that does not use line info
-void EditorCtrl::StartChange() {
- do_freeze = false;
- change_pos = m_lines.GetPos();
- cxLOCKDOC_WRITE(m_doc)
- doc.Freeze();
- change_doc_id = doc.GetDocument();
+bool EditorCtrl::InChange() const {
+ cxLOCKDOC_READ(m_doc)
+ return doc.InChange();
cxENDLOCK
- change_toppos = m_lines.GetPosFromXY(0, scrollPos+1);
}
-void EditorCtrl::EndChange() {
- wxASSERT(do_freeze == false);
+size_t EditorCtrl::GetChangeLevel() const {
+ cxLOCKDOC_READ(m_doc)
+ return doc.GetChangeLevel();
+ cxENDLOCK
+}
- doc_id di;
+void EditorCtrl::StartChange() {
cxLOCKDOC_WRITE(m_doc)
- doc.Freeze();
- di = doc.GetDocument();
+ doc.StartChange(true/*doNotify*/);
cxENDLOCK
+}
- // Invalidate all stylers
- StylersInvalidate();
-
- if (change_doc_id.SameDoc(di)) {
- // If we are still in the same document, we want to find
- // matching positions and selections
-
- if (change_doc_id.version_id == di.version_id) return;
-
- vector<interval> oldsel = m_lines.GetSelections();
- m_lines.ReLoadText();
-
- // re-set the width
- UpdateEditorWidth();
-
- RemapPos(change_doc_id, change_pos, oldsel, change_toppos);
- }
- else {
- scrollPos = 0;
- m_lines.ReLoadText();
-
- // re-set the width
- UpdateEditorWidth();
- }
-
- do_freeze = true;
+void EditorCtrl::EndChange(int forceTo) {
+ cxLOCKDOC_WRITE(m_doc)
+ doc.EndChange(forceTo);
+ cxENDLOCK
}
bool EditorCtrl::Show(bool show) {
@@ -9849,10 +9824,12 @@ void EditorCtrl::PlayMacro() {
void EditorCtrl::PlayMacro(const eMacro& macro) {
if (m_macro.IsRecording()) m_macro.EndRecording(); // avoid endless loop
+ StartChange(); // group changes as a single change
for (size_t i = 0; i < macro.GetCount(); ++i) {
const eMacroCmd& cmd = macro.GetCommand(i);
PlayCommand(cmd);
}
+ EndChange();
}
wxVariant EditorCtrl::PlayCommand(const eMacroCmd& cmd) {
View
4 src/EditorCtrl.h
@@ -86,7 +86,9 @@ class EditorCtrl : public KeyHookable<wxControl>,
// Change state
void StartChange();
- void EndChange();
+ void EndChange(int forceTo=-1);
+ bool InChange() const;
+ size_t GetChangeLevel() const;
// Document info
unsigned int GetLength() const;
Please sign in to comment.
Something went wrong with that request. Please try again.