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>