Annotation of modules/damieng/graphical_editor/daxe/lib/src/toolbar.dart, revision 1.4

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>