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