Annotation of modules/damieng/graphical_editor/daxe/lib/src/toolbar.dart, revision 1.2
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: List<x.Element> refs = info.possibleRefs;
377: if (info.findValidRef(validRefs))
378: button.enable();
379: else
380: button.disable();
381: }
382:
383: addStyleButton(Config cfg, ToolbarBox box, x.Element ref, String icon, [String shortcut=null]) {
384: ToolbarButton button = new ToolbarButton(_documentationFor(ref), icon, null, dnStyleButtonUpdate,
385: data:new ToolbarStyleInfo([ref], null, null), shortcut:shortcut);
386: button.action = () {
387: if (button.selected) {
388: Position start = page.getSelectionStart();
389: Position end = page.getSelectionEnd();
390: if (start == end && start.dn is DNText && start.dn.parent.ref == ref &&
391: start.dnOffset == start.dn.offsetLength && start.dn.nextSibling == null) {
392: // we are at the end of the style
393: // just move the cursor position outside of the style
394: DaxeNode styleNode = start.dn.parent;
395: page.moveCursorTo(new Position(styleNode.parent, styleNode.parent.offsetOf(styleNode)+1));
396: page.updateAfterPathChange();
397: } else
398: DNStyle.removeStylesFromSelection(ref);
399: } else {
400: DNStyle.applyStyleInsideSelection(ref);
401: }
402: };
403: box.add(button);
404: }
405:
406: static void dnStyleButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
407: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
408: // DNStyle, style with no css (as with the b element)
409: ToolbarStyleInfo info = button.data;
410: List<x.Element> refs = info.possibleRefs;
411: bool foundAncestor = false;
412: for (x.Element possibleRef in refs) {
413: if (ancestorRefs.contains(possibleRef)) {
414: foundAncestor = true;
415: break;
416: }
417: }
418: if (foundAncestor) {
419: button.enable();
420: button.select();
421: } else {
422: if (selectedNode != null && refs.contains(selectedNode.ref))
423: button.select();
424: else
425: button.deselect();
426: if (info.findValidRef(validRefs))
427: button.enable();
428: else
429: button.disable();
430: }
431: }
432:
433: static void styleSpanButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
434: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
435: // DNSpanStyle, span style
436: ToolbarStyleInfo info = button.data;
437: x.Element ref = info.possibleRefs[0];
438: bool foundAncestor = false;
439: for (DaxeNode n = parent; n != null; n = n.parent) {
440: if (n.ref == ref && (n as DNStyleSpan).matchesCss(info.cssName, info.cssValue)) {
441: foundAncestor = true;
442: break;
443: }
444: }
445: if (foundAncestor) {
446: button.enable();
447: button.select();
448: } else {
449: if (selectedNode != null && ref == selectedNode.ref &&
450: (selectedNode as DNStyleSpan).matchesCss(info.cssName, info.cssValue)) {
451: button.select();
452: } else {
453: button.deselect();
454: }
455: if (validRefs.contains(ref))
456: button.enable();
457: else
458: button.disable();
459: }
460: }
461:
462: addParagraphCssButton(ToolbarBox alignBox, String cssName, String cssValue,
463: String title, String icon) {
464: ToolbarButton button = new ToolbarButton(title, icon,
465: null, paragraphButtonUpdate, data:new ToolbarStyleInfo(doc.hiddenParaRefs, cssName, cssValue));
466: button.action = () {
467: if (button.selected) {
468: DNHiddenP.removeStyleFromSelection(cssName);
469: } else {
470: DNHiddenP.applyStyleToSelection(cssName, cssValue);
471: }
472: };
473: alignBox.add(button);
474: }
475:
476: static void paragraphButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
477: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
478: ToolbarStyleInfo info = button.data;
479: bool foundAncestor = false;
480: for (DaxeNode n = parent; n != null; n = n.parent) {
481: if (doc.hiddenParaRefs.contains(n.ref)) {
482: if ((n as DNHiddenP).matchesCss(info.cssName, info.cssValue)) {
483: foundAncestor = true;
484: break;
485: }
486: }
487: }
488: if (foundAncestor) {
489: button.enable();
490: button.select();
491: } else {
492: if (selectedNode != null && doc.hiddenParaRefs.contains(selectedNode.ref) &&
493: (selectedNode as DNHiddenP).matchesCss(info.cssName, info.cssValue)) {
494: button.select();
495: } else {
496: button.deselect();
497: }
498: if (DNHiddenP.paragraphsInSelection().length > 0)
499: button.enable();
500: else
501: button.disable();
502: }
503: }
504:
505: static void listButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
506: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
507: // toggle list button
508: ToolbarStyleInfo info = button.data;
509: List<x.Element> refs = info.possibleRefs;
510: bool foundAncestor = false;
511: for (DaxeNode n = parent; n != null; n = n.parent) {
512: if (refs.contains(n.ref)) {
513: foundAncestor = true;
514: break;
515: }
516: }
517: if (foundAncestor) {
518: button.enable();
519: button.select();
520: } else {
521: button.deselect();
522: if (info.findValidRef(validRefs))
523: button.enable();
524: else
525: button.disable();
526: }
527: }
528:
529: static void riseListLevelButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
530: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
531: Position start = page.getSelectionStart();
532: DaxeNode dn = start.dn;
533: while (dn != null && dn is! DNWItem)
534: dn = dn.parent;
535: if (dn != null)
536: button.enable();
537: else
538: button.disable();
539: }
540:
541: static void lowerListLevelButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
542: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
543: Position start = page.getSelectionStart();
544: DaxeNode dn = start.dn;
545: while (dn != null && dn is! DNWItem)
546: dn = dn.parent;
547: if (dn == null || dn.previousSibling == null)
548: button.disable();
549: else
550: button.enable();
551: }
552:
553: static void insertLinkButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
554: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
555: ToolbarStyleInfo info = button.data;
556: if (page.getSelectionStart().dn is DNText && info.findValidRef(validRefs))
557: button.enable();
558: else
559: button.disable();
560: }
561:
562: static void removeLinkButtonUpdate(ToolbarButton button, DaxeNode parent, DaxeNode selectedNode,
563: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
564: ToolbarStyleInfo info = button.data;
565: List<x.Element> refs = info.possibleRefs;
566: bool foundAncestor = false;
567: for (x.Element possibleRef in refs) {
568: if (ancestorRefs.contains(possibleRef)) {
569: foundAncestor = true;
570: break;
571: }
572: }
573: if (foundAncestor)
574: button.enable();
575: else
576: button.disable();
577: }
578:
579: static void styleMenuUpdate(ToolbarMenu tbmenu, DaxeNode parent, DaxeNode selectedNode,
580: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
581: Menu menu = tbmenu.menu;
582: MenuItem selectedItem = null;
583: for (MenuItem menuItem in menu.items) {
584: if (menuItem.data is ToolbarStyleInfo) {
585: ToolbarStyleInfo info = menuItem.data;
586: x.Element ref = info.possibleRefs[0];
587: String cssName = info.cssName;
588: String cssValue = info.cssValue;
589: if (doc.hiddenParaRefs.contains(ref)) {
590: // paragraph style
591: bool foundAncestor = false;
592: for (DaxeNode n = parent; n != null; n = n.parent) {
593: if (doc.hiddenParaRefs.contains(n.ref) && (n as DNHiddenP).matchesCss(cssName, cssValue)) {
594: foundAncestor = true;
595: break;
596: }
597: }
598: if (foundAncestor) {
599: menuItem.enable();
600: selectedItem = menuItem;
601: menuItem.check();
602: } else {
603: if (selectedNode != null && doc.hiddenParaRefs.contains(selectedNode.ref) &&
604: (selectedNode as DNHiddenP).matchesCss(cssName, cssValue)) {
605: selectedItem = menuItem;
606: menuItem.check();
607: } else {
608: menuItem.uncheck();
609: }
610: if (DNHiddenP.paragraphsInSelection().length > 0)
611: menuItem.enable();
612: else
613: menuItem.disable();
614: }
615: } else if (doc.cfg.elementDisplayType(ref) == 'style') {
616: // DNStyle
617: if (ancestorRefs.contains(ref)) {
618: menuItem.enable();
619: selectedItem = menuItem;
620: } else {
621: if (selectedNode != null && ref == selectedNode.ref)
622: selectedItem = menuItem;
623: if (validRefs.contains(ref))
624: menuItem.enable();
625: else
626: menuItem.disable();
627: }
628: } else if (doc.cfg.elementDisplayType(ref) == 'stylespan') {
629: // DNSpanStyle
630: bool foundAncestor = false;
631: for (DaxeNode n = parent; n != null; n = n.parent) {
632: if (n.ref == ref && (n as DNStyleSpan).matchesCss(cssName, cssValue)) {
633: foundAncestor = true;
634: break;
635: }
636: }
637: if (foundAncestor) {
638: menuItem.enable();
639: selectedItem = menuItem;
640: menuItem.check();
641: } else {
642: if (selectedNode != null && ref == selectedNode.ref &&
643: (selectedNode as DNStyleSpan).matchesCss(cssName, cssValue)) {
644: selectedItem = menuItem;
645: menuItem.check();
646: } else {
647: menuItem.uncheck();
648: }
649: if (validRefs.contains(ref))
650: menuItem.enable();
651: else
652: menuItem.disable();
653: }
654: } else if (ref != null) {
655: // element insert
656: if (validRefs.contains(ref))
657: menuItem.enable();
658: else
659: menuItem.disable();
660: }
661: }
662: }
663: if (selectedItem == null)
664: menu.title = tbmenu.title;
665: else
666: menu.title = selectedItem.title;
667: }
668:
669: static void insertMenuUpdate(ToolbarMenu tbmenu, DaxeNode parent, DaxeNode selectedNode,
670: List<x.Element> validRefs, List<x.Element> ancestorRefs) {
671: Menu menu = tbmenu.menu;
672: for (MenuItem menuItem in menu.items) {
673: if (menuItem.data is ToolbarStyleInfo) {
674: ToolbarStyleInfo info = menuItem.data;
675: List<x.Element> refs = info.possibleRefs;
676: if (refs != null && refs.length > 0) {
677: // element insert
678: if (info.findValidRef(validRefs))
679: menuItem.enable();
680: else
681: menuItem.disable();
682: }
683: }
684: }
685: }
686:
687: void update(DaxeNode parent, List<x.Element> validRefs) {
688: List<x.Element> ancestorRefs = new List<x.Element>();
689: for (DaxeNode n = parent; n != null; n = n.parent)
690: ancestorRefs.add(n.ref);
691: DaxeNode selectedNode = null;// will be !=null when the selection matches a full element
692: Position start = page.getSelectionStart();
693: Position end = page.getSelectionEnd();
694: if (start.dn is! DNText && start.dn.offsetLength > start.dnOffset) {
695: if (end == new Position(start.dn, start.dnOffset + 1))
696: selectedNode = start.dn.childAtOffset(start.dnOffset);
697: }
698: // update buttons
699: for (ToolbarButton button in buttons) {
700: if (button.update != null)
701: button.update(button, parent, selectedNode, validRefs, ancestorRefs);
702: }
703: // update menus
704: for (ToolbarItem tbitem in items) {
705: if (tbitem is ToolbarMenu) {
706: tbitem.update(tbitem, parent, selectedNode, validRefs, ancestorRefs);
707: }
708: }
709: }
710:
711: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>