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

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

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