Annotation of modules/damieng/graphical_editor/daxe/lib/src/toolbar.dart, revision 1.4
1.1 damieng 1: /*
2: This file is part of Daxe.
3:
4: Daxe is free software: you can redistribute it and/or modify
5: it under the terms of the GNU General Public License as published by
6: the Free Software Foundation, either version 3 of the License, or
7: (at your option) any later version.
8:
9: Daxe is distributed in the hope that it will be useful,
10: but WITHOUT ANY WARRANTY; without even the implied warranty of
11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: GNU General Public License for more details.
13:
14: You should have received a copy of the GNU General Public License
15: along with Daxe. If not, see <http://www.gnu.org/licenses/>.
16: */
17:
18: part of daxe;
19:
20: class Toolbar {
21: List<ToolbarItem> items;
22: List<x.Element> cacheRefs = null;
23: static final String iconPath = 'packages/daxe/images/toolbar/';
24:
25: Toolbar([Config cfg]) {
26: items = new List<ToolbarItem>();
27: if (doc.saveURL != null) {
28: ToolbarBox documentBox = new ToolbarBox();
29: documentBox.add(new ToolbarButton(Strings.get('menu.save'), iconPath + 'document_save.png',
30: () => page.save(), null));
31: items.add(documentBox);
32: }
33: ToolbarBox historyBox = new ToolbarBox();
34: historyBox.add(new ToolbarButton(Strings.get('undo.undo'), iconPath + 'history_undo.png',
35: () => doc.undo(), null, data:"undo", enabled:false));
36: historyBox.add(new ToolbarButton(Strings.get('undo.redo'), iconPath + 'history_redo.png',
37: () => doc.redo(), null, data:"redo", enabled:false));
38: items.add(historyBox);
1.4 ! damieng 39: // We could do a browser check here, but that requires another library...
! 40: // We would display these buttons only for Chrome 42+, Firefox 41+,
! 41: // IE 9+, Opera 29+ (Safari does not support it)
! 42: ToolbarBox editBox = new ToolbarBox();
! 43: editBox.add(new ToolbarButton(Strings.get('toolbar.cut'), iconPath + 'cut.png',
! 44: () => page.cursor.clipboardCut(), null, data:'cut', enabled:true));
! 45: editBox.add(new ToolbarButton(Strings.get('toolbar.copy'), iconPath + 'copy.png',
! 46: () => page.cursor.clipboardCopy(), null, data:'copy', enabled:true));
! 47: items.add(editBox);
1.1 damieng 48: ToolbarBox findBox = new ToolbarBox();
49: findBox.add(new ToolbarButton(Strings.get('find.find_replace'), iconPath + 'find.png',
50: () => (new FindDialog()).show(), null));
51: items.add(findBox);
52: if (cfg != null) {
53: // Buttons to insert new elements
54: List<x.Element> refs = cfg.elementsWithType('fichier');
55: if (refs != null && refs.length > 0) {
1.2 damieng 56: ToolbarBox fileBox = new ToolbarBox();
57: addInsertButton(cfg, fileBox, refs, iconPath + 'insert_image.png');
58: items.add(fileBox);
1.1 damieng 59: }
1.2 damieng 60: ToolbarBox mathBox = new ToolbarBox();
1.1 damieng 61: refs = cfg.elementsWithType('equationmem');
62: if (refs != null && refs.length > 0) {
1.2 damieng 63: addInsertButton(cfg, mathBox, refs, iconPath + 'equation.png');
1.1 damieng 64: }
65: refs = cfg.elementsWithType('symbole2');
66: if (refs != null && refs.length > 0) {
1.2 damieng 67: addInsertButton(cfg, mathBox, refs, iconPath + 'insert_symbol.png');
68: } else {
69: addUnicodeSymbolButton(mathBox);
1.1 damieng 70: }
1.2 damieng 71: items.add(mathBox);
72: ToolbarBox insertBox = new ToolbarBox();
1.1 damieng 73: refs = cfg.elementsWithType('tabletexte');
74: if (refs != null && refs.length > 0) {
75: addInsertButton(cfg, insertBox, refs, iconPath + 'insert_table.png');
76: }
77: refs = cfg.elementsWithType('liste');
78: if (refs != null && refs.length > 0) {
79: addInsertButton(cfg, insertBox, refs, iconPath + 'ul.png');
80: }
81: items.add(insertBox);
82: // List buttons
83: List<x.Element> ulRefs = DNWList.ulRefs();
84: List<x.Element> olRefs = DNWList.olRefs();
85: if (ulRefs.length > 0 || olRefs.length > 0) {
86: ToolbarBox listBox = new ToolbarBox();
87: if (ulRefs.length > 0) {
88: ToolbarButton button = new ToolbarButton(_documentationFor(ulRefs[0]), iconPath + 'ul.png',
89: null, listButtonUpdate, data:new ToolbarStyleInfo(ulRefs, null, null));
90: button.action = () {
91: if (button.selected)
92: DNWList.riseLevel();
93: else
94: DNWList.addList((button.data as ToolbarStyleInfo).validRef);
95: };
96: listBox.add(button);
97: }
98: if (olRefs.length > 0) {
99: ToolbarButton button = new ToolbarButton(_documentationFor(olRefs[0]), iconPath + 'ol.png',
100: null, listButtonUpdate, data:new ToolbarStyleInfo(olRefs, null, null));
101: button.action = () {
102: if (button.selected)
103: DNWList.riseLevel();
104: else
105: DNWList.addList((button.data as ToolbarStyleInfo).validRef);
106: };
107: listBox.add(button);
108: }
109: listBox.add(new ToolbarButton(Strings.get('toolbar.rise_list_level'), iconPath + 'list_rise_level.png',
110: () => DNWList.riseLevel(), riseListLevelButtonUpdate, data:'rise_list_level'));
111: bool possibleListInItem = true; // will be true if it is always possible to have a list in an item of the same type
112: for (x.Element ulRef in ulRefs)
113: if (doc.cfg.findSubElement(DNWList.findItemRef(ulRef), ulRefs) == null)
114: possibleListInItem = false;
115: for (x.Element olRef in olRefs)
116: if (doc.cfg.findSubElement(DNWList.findItemRef(olRef), olRefs) == null)
117: possibleListInItem = false;
118: if (possibleListInItem)
119: listBox.add(new ToolbarButton(Strings.get('toolbar.lower_list_level'), iconPath + 'list_lower_level.png',
120: () => DNWList.lowerLevel(), lowerListLevelButtonUpdate, data:'lower_list_level'));
121: items.add(listBox);
122: }
123: // Link/Anchor buttons
124: List<x.Element> aRefs = DNAnchor.aRefs();
125: if (aRefs != null && aRefs.length > 0) {
126: ToolbarBox anchorBox = new ToolbarBox();
127: ToolbarButton button = new ToolbarButton(Strings.get('toolbar.insert_link'),
128: iconPath + 'add_link.png',
129: null, insertLinkButtonUpdate,
130: data:new ToolbarStyleInfo(aRefs, null, null));
131: button.action = () => DNAnchor.addLink((button.data as ToolbarStyleInfo).validRef);
132: anchorBox.add(button);
133: button = new ToolbarButton(Strings.get('toolbar.remove_link'),
134: iconPath + 'remove_link.png',
135: () => DNAnchor.removeLink(), removeLinkButtonUpdate,
136: data:new ToolbarStyleInfo(aRefs, null, null));
137: anchorBox.add(button);
138: button = new ToolbarButton(Strings.get('toolbar.insert_anchor'),
139: iconPath + 'anchor.png',
140: null, insertButtonUpdate,
141: data:new ToolbarStyleInfo(aRefs, null, null));
142: button.action = () => DNAnchor.addAnchor((button.data as ToolbarStyleInfo).validRef);
143: anchorBox.add(button);
144: items.add(anchorBox);
145: }
146: // Style buttons
147: ToolbarBox styleBox = new ToolbarBox();
148: List<x.Element> all = cfg.allElementsList();
149: for (x.Element ref in all) {
150: String dtype = cfg.elementDisplayType(ref);
151: if (dtype == 'style') {
152: String style = cfg.elementParameterValue(ref, 'style', null);
153: if (style == 'GRAS') {
154: addStyleButton(cfg, styleBox, ref, iconPath + 'style_bold.png', 'B');
155: } else if (style == 'ITALIQUE') {
156: addStyleButton(cfg, styleBox, ref, iconPath + 'style_italic.png', 'I');
157: } else if (style == 'EXPOSANT') {
158: addStyleButton(cfg, styleBox, ref, iconPath + 'style_superscript.png');
159: } else if (style == 'INDICE') {
160: addStyleButton(cfg, styleBox, ref, iconPath + 'style_subscript.png');
161: } else if (style == 'BARRE') {
162: addStyleButton(cfg, styleBox, ref, iconPath + 'style_strikethrough.png');
163: } else if (style == 'SOULIGNE') {
164: addStyleButton(cfg, styleBox, ref, iconPath + 'style_underline.png');
165: }
166: }
167: }
168: if (styleBox.length > 0) {
169: styleBox.add(new ToolbarButton(Strings.get('toolbar.remove_styles'), iconPath + 'remove_styles.png',
170: () => DNStyle.removeStylesFromSelection(), null, data:"remove_styles"));
171: items.add(styleBox);
172: }
173: if (doc.hiddenParaRefs != null) {
174: // Align buttons
175: String pStyleAtt = doc.cfg.elementParameterValue(doc.hiddenParaRefs[0], 'styleAtt', 'style');
176: // check if style attribute is allowed for hidden paragraphs
177: List<x.Element> attRefs = doc.cfg.elementAttributes(doc.hiddenParaRefs[0]);
178: bool found = false;
179: for (x.Element attRef in attRefs) {
180: if (doc.cfg.attributeName(attRef) == pStyleAtt) {
181: found = true;
182: break;
183: }
184: }
185: if (found) {
186: ToolbarBox alignBox = new ToolbarBox();
187: addParagraphCssButton(alignBox, 'text-align', 'left',
188: Strings.get('toolbar.align_left'), iconPath + 'align_left.png');
189: addParagraphCssButton(alignBox, 'text-align', 'right',
190: Strings.get('toolbar.align_right'), iconPath + 'align_right.png');
191: addParagraphCssButton(alignBox, 'text-align', 'center',
192: Strings.get('toolbar.align_center'), iconPath + 'align_center.png');
193: addParagraphCssButton(alignBox, 'text-align', 'justify',
194: Strings.get('toolbar.align_justify'), iconPath + 'align_justify.png');
195: items.add(alignBox);
196: }
197: }
198: x.Element spanRef = DNStyleSpan.styleSpanRef();
199: if (spanRef != null) {
200: // Font menu
201: List<String> fonts = ['serif', 'sans-serif', 'cursive', 'fantasy', 'monospace'];
202: ToolbarMenu tbmenu = _makeStyleToolbarMenu(Strings.get('toolbar.font'), "font-family", fonts);
203: items.add(tbmenu);
204: /*
205: A size menu is a bad idea: larger font sizes are used for titles and it is
206: important to be able to extract titles automatically
207:
208: // Size menu
209: List<String> sizes = ['8', '9', '10', '11', '12', '14', '16', '18',
210: '20', '24', '28', '32', '36', '48', '72'];
211: tbmenu = _makeStyleToolbarMenu(Strings.get('toolbar.size'), "font-size", sizes, "px");
212: items.add(tbmenu);
213: */
214: }
215: }
216: }
217:
218: ToolbarMenu _makeStyleToolbarMenu(String title, String cssName, List<String> cssValues,
219: [String cssUnit]) {
220: Menu menu = new Menu(title);
221: menu.parent = this;
222: x.Element styleRef = DNStyleSpan.styleSpanRef();
223: for (String cssValue in cssValues) {
224: String cssValueWithUnit = cssValue;
225: if (cssUnit != null)
226: cssValueWithUnit += cssUnit;
227: MenuItem menuItem = new MenuItem(cssValue, null,
228: data:new ToolbarStyleInfo([styleRef], cssName, cssValueWithUnit));
229: menuItem.action = () {
230: if (menuItem.checked) {
231: Position start = page.getSelectionStart();
232: Position end = page.getSelectionEnd();
233: if (start == end && start.dn is DNText && start.dn.parent.ref == styleRef &&
234: (start.dn.parent as DNStyle).matchesCss(cssName, cssValueWithUnit) &&
235: start.dnOffset == start.dn.offsetLength && start.dn.nextSibling == null) {
236: // we are at the end of the style
237: // just move the cursor position outside of the style
238: DaxeNode styleNode = start.dn.parent;
239: page.moveCursorTo(new Position(styleNode.parent, styleNode.parent.offsetOf(styleNode)+1));
240: page.updateAfterPathChange();
241: } else
242: DNStyle.removeStylesFromSelection(styleRef, cssName);
243: } else {
244: DNStyle.removeAndApplyStyleToSelection(styleRef, cssName, cssValueWithUnit);
245: }
246: };
247: menu.add(menuItem);
248: }
249: ToolbarMenu tbmenu = new ToolbarMenu(menu, styleMenuUpdate, this);
250: return(tbmenu);
251: }
252:
253: add(ToolbarItem item) {
254: items.add(item);
255: }
256:
257: insert(ToolbarItem item, int position) {
258: items.insert(position, item);
259: }
260:
261: remove(int position) {
262: items.remove(position);
263: }
264:
265: List<ToolbarButton> get buttons {
266: List<ToolbarButton> buttons = new List<ToolbarButton>();
267: for (ToolbarItem item in items) {
268: if (item is ToolbarBox)
269: buttons.addAll(item.buttons);
270: }
271: return(buttons);
272: }
273:
274: /**
275: * Returns a list of all element references used in the toolbar.
276: */
277: List<x.Element> elementRefs() {
278: if (cacheRefs != null)
279: return(cacheRefs);
280: List<x.Element> list = new List<x.Element>();
281: for (ToolbarItem item in items) {
282: if (item is ToolbarBox) {
283: for (ToolbarButton button in item.buttons) {
284: if (button.data is ToolbarStyleInfo) {
285: ToolbarStyleInfo info = button.data;
286: if (info.possibleRefs != null)
287: list.addAll(info.possibleRefs);
288: }
289: }
290: } else if (item is ToolbarMenu) {
291: Menu menu = item.menu;
292: for (MenuItem menuItem in menu.items) {
293: if (menuItem.data is ToolbarStyleInfo) {
294: ToolbarStyleInfo info = menuItem.data;
295: if (info.possibleRefs != null)
296: list.addAll(info.possibleRefs);
297: }
298: }
299: }
300: }
301: cacheRefs = list;
302: return(list);
303: }
304:
305: h.Element html() {
306: h.DivElement div = new h.DivElement();
307: div.classes.add('toolbar');
308: for (ToolbarItem item in items) {
309: div.append(item.html());
310: }
311: return(div);
312: }
313:
314: String _documentationFor(x.Element ref) {
315: String documentation = doc.cfg.documentation(ref);
316: if (documentation == null)
317: documentation = doc.cfg.elementTitle(ref);
318: return(documentation);
319: }
320:
321: addInsertButton(Config cfg, ToolbarBox box, List<x.Element> refs, String icon) {
322: ToolbarButton button = new ToolbarButton(_documentationFor(refs[0]), icon,
323: null, insertButtonUpdate,
324: data:new ToolbarStyleInfo(refs, null, null));
325: button.action = () => doc.insertNewNode((button.data as ToolbarStyleInfo).validRef, 'element');
326: box.add(button);
327: }
328:
1.2 damieng 329: addUnicodeSymbolButton(ToolbarBox box) {
330: ToolbarButton button = new ToolbarButton(Strings.get('toolbar.symbol'), iconPath + 'insert_symbol.png',
331: SymbolButtonClick, symbolButtonUpdate);
332: box.add(button);
333: }
334:
335: static SymbolButtonClick() {
336: SymbolDialog dlg;
337: dlg = new SymbolDialog(() {
338: String char = dlg.getChar();
339: if (char != null) {
340: doc.insertNewString(char, false);
341: }
342: });
343: dlg.show();
344: }
345:
346: static void symbolButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
347: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
348: // check if text is allowed here
349: bool problem = false;
350: Position selectionStart = page.getSelectionStart();
351: Position selectionEnd = page.getSelectionEnd();
352: if (selectionStart == null) {
353: problem = true;
354: } else {
355: DaxeNode parent = selectionStart.dn;
356: if (parent.nodeType == DaxeNode.TEXT_NODE)
357: parent = parent.parent;
358: if (parent.userCannotEdit)
359: problem = true;
360: else {
361: if (parent.nodeType == DaxeNode.DOCUMENT_NODE)
362: problem = true;
363: else if (parent.ref != null && !doc.cfg.canContainText(parent.ref)) {
364: if (doc.hiddenParaRefs != null) {
365: x.Element hiddenp = doc.cfg.findSubElement(parent.ref, doc.hiddenParaRefs);
366: if (hiddenp != null && selectionStart == selectionEnd) {
367: // we will just have to insert a hidden paragraph
368: } else
369: problem = true;
370: } else
371: problem = true;
372: }
373: }
374: }
375: if (problem)
376: button.disable();
377: else
378: button.enable();
379: }
380:
1.1 damieng 381: static void insertButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
382: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
383: // element insert
384: ToolbarStyleInfo info = button.data;
385: if (info.findValidRef(validRefs))
386: button.enable();
387: else
388: button.disable();
389: }
390:
391: addStyleButton(Config cfg, ToolbarBox box, x.Element ref, String icon, [String shortcut=null]) {
392: ToolbarButton button = new ToolbarButton(_documentationFor(ref), icon, null, dnStyleButtonUpdate,
393: data:new ToolbarStyleInfo([ref], null, null), shortcut:shortcut);
394: button.action = () {
395: if (button.selected) {
396: Position start = page.getSelectionStart();
397: Position end = page.getSelectionEnd();
398: if (start == end && start.dn is DNText && start.dn.parent.ref == ref &&
399: start.dnOffset == start.dn.offsetLength && start.dn.nextSibling == null) {
400: // we are at the end of the style
401: // just move the cursor position outside of the style
402: DaxeNode styleNode = start.dn.parent;
403: page.moveCursorTo(new Position(styleNode.parent, styleNode.parent.offsetOf(styleNode)+1));
404: page.updateAfterPathChange();
405: } else
406: DNStyle.removeStylesFromSelection(ref);
407: } else {
408: DNStyle.applyStyleInsideSelection(ref);
409: }
410: };
411: box.add(button);
412: }
413:
414: static void dnStyleButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
415: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
416: // DNStyle, style with no css (as with the b element)
417: ToolbarStyleInfo info = button.data;
418: List<x.Element> refs = info.possibleRefs;
419: bool foundAncestor = false;
420: for (x.Element possibleRef in refs) {
421: if (ancestorRefs.contains(possibleRef)) {
422: foundAncestor = true;
423: break;
424: }
425: }
426: if (foundAncestor) {
427: button.enable();
428: button.select();
429: } else {
430: if (selectedNode != null && refs.contains(selectedNode.ref))
431: button.select();
432: else
433: button.deselect();
434: if (info.findValidRef(validRefs))
435: button.enable();
436: else
437: button.disable();
438: }
439: }
440:
441: static void styleSpanButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
442: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
443: // DNSpanStyle, span style
444: ToolbarStyleInfo info = button.data;
445: x.Element ref = info.possibleRefs[0];
446: bool foundAncestor = false;
447: for (DaxeNode n = parent; n != null; n = n.parent) {
448: if (n.ref == ref && (n as DNStyleSpan).matchesCss(info.cssName, info.cssValue)) {
449: foundAncestor = true;
450: break;
451: }
452: }
453: if (foundAncestor) {
454: button.enable();
455: button.select();
456: } else {
457: if (selectedNode != null && ref == selectedNode.ref &&
458: (selectedNode as DNStyleSpan).matchesCss(info.cssName, info.cssValue)) {
459: button.select();
460: } else {
461: button.deselect();
462: }
463: if (validRefs.contains(ref))
464: button.enable();
465: else
466: button.disable();
467: }
468: }
469:
470: addParagraphCssButton(ToolbarBox alignBox, String cssName, String cssValue,
471: String title, String icon) {
472: ToolbarButton button = new ToolbarButton(title, icon,
473: null, paragraphButtonUpdate, data:new ToolbarStyleInfo(doc.hiddenParaRefs, cssName, cssValue));
474: button.action = () {
475: if (button.selected) {
476: DNHiddenP.removeStyleFromSelection(cssName);
477: } else {
478: DNHiddenP.applyStyleToSelection(cssName, cssValue);
479: }
480: };
481: alignBox.add(button);
482: }
483:
484: static void paragraphButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
485: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
486: ToolbarStyleInfo info = button.data;
487: bool foundAncestor = false;
488: for (DaxeNode n = parent; n != null; n = n.parent) {
489: if (doc.hiddenParaRefs.contains(n.ref)) {
490: if ((n as DNHiddenP).matchesCss(info.cssName, info.cssValue)) {
491: foundAncestor = true;
492: break;
493: }
494: }
495: }
496: if (foundAncestor) {
497: button.enable();
498: button.select();
499: } else {
500: if (selectedNode != null && doc.hiddenParaRefs.contains(selectedNode.ref) &&
501: (selectedNode as DNHiddenP).matchesCss(info.cssName, info.cssValue)) {
502: button.select();
503: } else {
504: button.deselect();
505: }
506: if (DNHiddenP.paragraphsInSelection().length > 0)
507: button.enable();
508: else
509: button.disable();
510: }
511: }
512:
513: static void listButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
514: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
515: // toggle list button
516: ToolbarStyleInfo info = button.data;
517: List<x.Element> refs = info.possibleRefs;
518: bool foundAncestor = false;
519: for (DaxeNode n = parent; n != null; n = n.parent) {
520: if (refs.contains(n.ref)) {
521: foundAncestor = true;
522: break;
523: }
524: }
525: if (foundAncestor) {
526: button.enable();
527: button.select();
528: } else {
529: button.deselect();
530: if (info.findValidRef(validRefs))
531: button.enable();
532: else
533: button.disable();
534: }
535: }
536:
537: static void riseListLevelButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
538: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
539: Position start = page.getSelectionStart();
540: DaxeNode dn = start.dn;
541: while (dn != null && dn is! DNWItem)
542: dn = dn.parent;
543: if (dn != null)
544: button.enable();
545: else
546: button.disable();
547: }
548:
549: static void lowerListLevelButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
550: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
551: Position start = page.getSelectionStart();
552: DaxeNode dn = start.dn;
553: while (dn != null && dn is! DNWItem)
554: dn = dn.parent;
555: if (dn == null || dn.previousSibling == null)
556: button.disable();
557: else
558: button.enable();
559: }
560:
561: static void insertLinkButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
562: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
563: ToolbarStyleInfo info = button.data;
564: if (page.getSelectionStart().dn is DNText && info.findValidRef(validRefs))
565: button.enable();
566: else
567: button.disable();
568: }
569:
570: static void removeLinkButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
571: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
572: ToolbarStyleInfo info = button.data;
573: List<x.Element> refs = info.possibleRefs;
574: bool foundAncestor = false;
575: for (x.Element possibleRef in refs) {
576: if (ancestorRefs.contains(possibleRef)) {
577: foundAncestor = true;
578: break;
579: }
580: }
581: if (foundAncestor)
582: button.enable();
583: else
584: button.disable();
585: }
586:
587: static void styleMenuUpdate(ToolbarMenu tbmenu, DaxeNode parent, DaxeNode selectedNode,
588: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
589: Menu menu = tbmenu.menu;
590: MenuItem selectedItem = null;
591: for (MenuItem menuItem in menu.items) {
592: if (menuItem.data is ToolbarStyleInfo) {
593: ToolbarStyleInfo info = menuItem.data;
594: x.Element ref = info.possibleRefs[0];
595: String cssName = info.cssName;
596: String cssValue = info.cssValue;
597: if (doc.hiddenParaRefs.contains(ref)) {
598: // paragraph style
599: bool foundAncestor = false;
600: for (DaxeNode n = parent; n != null; n = n.parent) {
601: if (doc.hiddenParaRefs.contains(n.ref) && (n as DNHiddenP).matchesCss(cssName, cssValue)) {
602: foundAncestor = true;
603: break;
604: }
605: }
606: if (foundAncestor) {
607: menuItem.enable();
608: selectedItem = menuItem;
609: menuItem.check();
610: } else {
611: if (selectedNode != null && doc.hiddenParaRefs.contains(selectedNode.ref) &&
612: (selectedNode as DNHiddenP).matchesCss(cssName, cssValue)) {
613: selectedItem = menuItem;
614: menuItem.check();
615: } else {
616: menuItem.uncheck();
617: }
618: if (DNHiddenP.paragraphsInSelection().length > 0)
619: menuItem.enable();
620: else
621: menuItem.disable();
622: }
623: } else if (doc.cfg.elementDisplayType(ref) == 'style') {
624: // DNStyle
625: if (ancestorRefs.contains(ref)) {
626: menuItem.enable();
627: selectedItem = menuItem;
628: } else {
629: if (selectedNode != null && ref == selectedNode.ref)
630: selectedItem = menuItem;
631: if (validRefs.contains(ref))
632: menuItem.enable();
633: else
634: menuItem.disable();
635: }
636: } else if (doc.cfg.elementDisplayType(ref) == 'stylespan') {
637: // DNSpanStyle
638: bool foundAncestor = false;
639: for (DaxeNode n = parent; n != null; n = n.parent) {
640: if (n.ref == ref && (n as DNStyleSpan).matchesCss(cssName, cssValue)) {
641: foundAncestor = true;
642: break;
643: }
644: }
645: if (foundAncestor) {
646: menuItem.enable();
647: selectedItem = menuItem;
648: menuItem.check();
649: } else {
650: if (selectedNode != null && ref == selectedNode.ref &&
651: (selectedNode as DNStyleSpan).matchesCss(cssName, cssValue)) {
652: selectedItem = menuItem;
653: menuItem.check();
654: } else {
655: menuItem.uncheck();
656: }
657: if (validRefs.contains(ref))
658: menuItem.enable();
659: else
660: menuItem.disable();
661: }
662: } else if (ref != null) {
663: // element insert
664: if (validRefs.contains(ref))
665: menuItem.enable();
666: else
667: menuItem.disable();
668: }
669: }
670: }
671: if (selectedItem == null)
672: menu.title = tbmenu.title;
673: else
674: menu.title = selectedItem.title;
675: }
676:
677: static void insertMenuUpdate(ToolbarMenu tbmenu, DaxeNode parent, DaxeNode selectedNode,
678: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
679: Menu menu = tbmenu.menu;
680: for (MenuItem menuItem in menu.items) {
681: if (menuItem.data is ToolbarStyleInfo) {
682: ToolbarStyleInfo info = menuItem.data;
683: List<x.Element> refs = info.possibleRefs;
684: if (refs != null && refs.length > 0) {
685: // element insert
686: if (info.findValidRef(validRefs))
687: menuItem.enable();
688: else
689: menuItem.disable();
690: }
691: }
692: }
693: }
694:
695: void update(DaxeNode parent, List<x.Element> validRefs) {
696: List<x.Element> ancestorRefs = new List<x.Element>();
697: for (DaxeNode n = parent; n != null; n = n.parent)
698: ancestorRefs.add(n.ref);
699: DaxeNode selectedNode = null;// will be !=null when the selection matches a full element
700: Position start = page.getSelectionStart();
701: Position end = page.getSelectionEnd();
702: if (start.dn is! DNText && start.dn.offsetLength > start.dnOffset) {
703: if (end == new Position(start.dn, start.dnOffset + 1))
704: selectedNode = start.dn.childAtOffset(start.dnOffset);
705: }
706: // update buttons
707: for (ToolbarButton button in buttons) {
708: if (button.update != null)
709: button.update(button, parent, selectedNode, validRefs, ancestorRefs);
710: }
711: // update menus
712: for (ToolbarItem tbitem in items) {
713: if (tbitem is ToolbarMenu) {
714: tbitem.update(tbitem, parent, selectedNode, validRefs, ancestorRefs);
715: }
716: }
717: }
718:
719: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>