collections: crash fixed; editors: notify about modified state change; tabs: allow renaming tab:

This commit is contained in:
Vadim Lopatin 2015-01-26 13:36:10 +03:00
parent d46febac11
commit 90e6d7e49c
3 changed files with 99 additions and 5 deletions

View File

@ -137,8 +137,8 @@ struct Collection(T, bool ownItems = false) {
T result = _items[index];
for (size_t i = index; i + 1 < _len; i++)
_items[i] = _items[i + 1];
_items[_len] = T.init;
_len--;
_items[_len] = T.init;
return result;
}
/// remove single item by value - if present in collection, returning true if item was found and removed
@ -185,6 +185,13 @@ struct Collection(T, bool ownItems = false) {
return remove(0);
}
/// peek first item
@property T peekFront() {
if (empty)
return T.init; // no items
return _items[0];
}
/// insert item at beginning of collection
void pushFront(T item) {
add(item, 0);
@ -197,6 +204,13 @@ struct Collection(T, bool ownItems = false) {
return remove(length - 1);
}
/// peek last item
@property T peekBack() {
if (empty)
return T.init; // no items
return _items[length - 1];
}
/// insert item at end of collection
void pushBack(T item) {
add(item);

View File

@ -325,6 +325,8 @@ enum EditAction {
/// replace whole content
ReplaceContent,
/// saved content
SaveContent,
}
/// edit operation details for EditableContent
@ -451,6 +453,18 @@ class UndoBuffer {
void clear() {
_undoList.clear();
_redoList.clear();
_savedState = null;
}
protected EditOperation _savedState;
/// current state is saved
void saved() {
_savedState = _undoList.peekBack;
}
/// returns true if content has been changed since last saved() or clear() call
@property bool modified() {
return _savedState !is _undoList.peekBack;
}
}
@ -459,6 +473,11 @@ interface EditableContentListener {
void onContentChange(EditableContent content, EditOperation operation, ref TextRange rangeBefore, ref TextRange rangeAfter, Object source);
}
/// Modified state change listener
interface ModifiedStateListener {
void onModifiedStateChange(Widget source, bool modified);
}
alias TokenPropString = ubyte[];
/// interface for custom syntax highlight
@ -476,6 +495,10 @@ class EditableContent {
_undoBuffer = new UndoBuffer();
}
@property bool modified() {
return _undoBuffer.modified;
}
protected UndoBuffer _undoBuffer;
protected SyntaxHighlighter _syntaxHighlighter;
@ -547,6 +570,14 @@ class EditableContent {
handleContentChange(new EditOperation(EditAction.ReplaceContent), rangeBefore, rangeAfter, this);
}
/// call listener to say that content is saved
void notifyContentSaved() {
TextRange rangeBefore;
TextRange rangeAfter;
// notify about content change
handleContentChange(new EditOperation(EditAction.SaveContent), rangeBefore, rangeAfter, this);
}
protected void updateTokenProps(int startLine, int endLine) {
clearTokenProps(startLine, endLine);
if (_syntaxHighlighter) {
@ -926,8 +957,8 @@ class EditableContent {
op.newRange = rangeAfter;
op.oldContent = oldcontent;
replaceRange(rangeBefore, rangeAfter, newcontent);
handleContentChange(op, rangeBefore, rangeAfter, source);
_undoBuffer.saveForUndo(op);
handleContentChange(op, rangeBefore, rangeAfter, source);
return true;
}
return false;
@ -1013,6 +1044,7 @@ class EditableContent {
}
// EOF
_format = lines.textFormat;
_undoBuffer.clear();
notifyContentReplaced();
return true;
} catch (Exception e) {
@ -1047,7 +1079,8 @@ class EditableContent {
for (int i = 0; i < _lines.length; i++) {
writer.writeLine(_lines[i]);
}
// EOF
_undoBuffer.saved();
notifyContentSaved();
return true;
} catch (Exception e) {
Log.e("Exception while trying to write file ", filename, " ", e.toString);
@ -1116,6 +1149,9 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
protected uint _foldingPaneWidth = 16;
protected uint _modificationMarksPaneWidth = 8;
/// Modified state change listener
Signal!ModifiedStateListener onModifiedStateChangeListener;
/// override to support modification of client rect after change, e.g. apply offset
override protected void handleClientRectLayout(ref Rect rc) {
updateLeftPaneWidth();
@ -1470,6 +1506,8 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
ensureCaretVisible();
correctCaretPos();
requestLayout();
} else if (operation.action == EditAction.SaveContent) {
// saved
} else {
_caretPos = rangeAfter.end;
_selectionRange.start = _caretPos;
@ -1481,9 +1519,15 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
// TODO: do something better (e.g. take into account ranges when correcting)
}
invalidate();
if (onModifiedStateChangeListener.assigned) {
if (_lastReportedModifiedState != content.modified) {
_lastReportedModifiedState = content.modified;
onModifiedStateChangeListener(this, content.modified);
}
}
return;
}
protected bool _lastReportedModifiedState;
/// get widget text
override @property dstring text() { return _content.text; }

View File

@ -122,7 +122,10 @@ class TabItemWidget : HorizontalLayout {
}
return true;
}
protected void setItem(TabItem item) {
@property TabItem item() {
return _item;
}
@property void setItem(TabItem item) {
_item = item;
if (item.iconId !is null) {
_icon.visibility = Visibility.Visible;
@ -304,6 +307,29 @@ class TabControl : WidgetGroupDefaultDrawing {
}
return this;
}
/// change name of tab
void renameTab(string ID, dstring name) {
int index = _items.indexById(id);
if (index >= 0) {
renameTab(index, name);
}
}
/// change name of tab
void renameTab(int index, dstring name) {
_items[index].text = name;
for (int i = 0; i < _children.count; i++) {
TabItemWidget widget = cast (TabItemWidget)_children[i];
if (widget && widget.item is _items[index]) {
widget.setItem(_items[index]);
requestLayout();
break;
}
}
}
/// add new tab
TabControl addTab(TabItem item, int index = -1, bool enableCloseButton = false) {
_items.insert(item, index);
@ -587,6 +613,16 @@ class TabWidget : VerticalLayout, TabHandler {
return this;
}
/// change name of tab
void renameTab(string ID, dstring name) {
_tabControl.renameTab(ID, name);
}
/// change name of tab
void renameTab(int index, dstring name) {
_tabControl.renameTab(index, name);
}
/// select tab
void selectTab(string ID, bool updateAccess = true) {
_tabHost.selectTab(ID, updateAccess);