File indexing completed on 2024-04-28 11:38:10

0001 /*
0002  * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
0003  *
0004  * Redistribution and use in source and binary forms, with or without
0005  * modification, are permitted provided that the following conditions
0006  * are met:
0007  * 1. Redistributions of source code must retain the above copyright
0008  *    notice, this list of conditions and the following disclaimer.
0009  * 2. Redistributions in binary form must reproduce the above copyright
0010  *    notice, this list of conditions and the following disclaimer in the
0011  *    documentation and/or other materials provided with the distribution.
0012  *
0013  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
0014  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0015  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0016  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
0017  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0018  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0019  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
0020  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
0021  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0022  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0023  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0024  */
0025 
0026 #include "jsediting.h"
0027 #include "editing/htmlediting_impl.h"
0028 #include "editor.h"
0029 
0030 #include "css/cssproperties.h"
0031 #include "css/cssvalues.h"
0032 #include "css/css_valueimpl.h"
0033 #include "xml/dom_selection.h"
0034 #include "xml/dom_docimpl.h"
0035 #include "dom/dom_string.h"
0036 
0037 #include "misc/khtml_partaccessor.h"
0038 
0039 #include <QHash>
0040 #include <QString>
0041 
0042 using khtml::TypingCommandImpl;
0043 using khtml::InsertListCommandImpl;
0044 //
0045 #define KPAC khtml::KHTMLPartAccessor
0046 
0047 #define DEBUG_COMMANDS
0048 
0049 namespace DOM
0050 {
0051 
0052 class DocumentImpl;
0053 
0054 struct CommandImp {
0055     bool (*execFn)(KHTMLPart *part, bool userInterface, const DOMString &value);
0056     bool (*enabledFn)(KHTMLPart *part);
0057     Editor::TriState(*stateFn)(KHTMLPart *part);
0058     DOMString(*valueFn)(KHTMLPart *part);
0059 };
0060 
0061 typedef QHash<QString, const CommandImp *> CommandDict;
0062 static CommandDict createCommandDictionary();
0063 
0064 bool JSEditor::execCommand(const CommandImp *cmd, bool userInterface, const DOMString &value)
0065 {
0066     if (!cmd || !cmd->enabledFn) {
0067         return false;
0068     }
0069     KHTMLPart *part = m_doc->part();
0070     if (!part) {
0071         return false;
0072     }
0073     m_doc->updateLayout();
0074     return cmd->enabledFn(part) && cmd->execFn(part, userInterface, value);
0075 }
0076 
0077 bool JSEditor::queryCommandEnabled(const CommandImp *cmd)
0078 {
0079     if (!cmd || !cmd->enabledFn) {
0080         return false;
0081     }
0082     KHTMLPart *part = m_doc->part();
0083     if (!part) {
0084         return false;
0085     }
0086     m_doc->updateLayout();
0087     return cmd->enabledFn(part);
0088 }
0089 
0090 bool JSEditor::queryCommandIndeterm(const CommandImp *cmd)
0091 {
0092     if (!cmd || !cmd->enabledFn) {
0093         return false;
0094     }
0095     KHTMLPart *part = m_doc->part();
0096     if (!part) {
0097         return false;
0098     }
0099     m_doc->updateLayout();
0100     return cmd->stateFn(part) == Editor::MixedTriState;
0101 }
0102 
0103 bool JSEditor::queryCommandState(const CommandImp *cmd)
0104 {
0105     if (!cmd || !cmd->enabledFn) {
0106         return false;
0107     }
0108     KHTMLPart *part = m_doc->part();
0109     if (!part) {
0110         return false;
0111     }
0112     m_doc->updateLayout();
0113     return cmd->stateFn(part) != Editor::FalseTriState;
0114 }
0115 
0116 bool JSEditor::queryCommandSupported(const CommandImp *cmd)
0117 {
0118     return cmd != nullptr;
0119 }
0120 
0121 DOMString JSEditor::queryCommandValue(const CommandImp *cmd)
0122 {
0123     if (!cmd || !cmd->enabledFn) {
0124         return DOMString();
0125     }
0126     KHTMLPart *part = m_doc->part();
0127     if (!part) {
0128         return DOMString();
0129     }
0130     m_doc->updateLayout();
0131     return cmd->valueFn(part);
0132 }
0133 
0134 // =============================================================================================
0135 
0136 // Private stuff
0137 
0138 static bool execStyleChange(KHTMLPart *part, int propertyID, const DOMString &propertyValue)
0139 {
0140     CSSStyleDeclarationImpl *style = new CSSStyleDeclarationImpl(nullptr);
0141     style->setProperty(propertyID, propertyValue);
0142     style->ref();
0143     part->editor()->applyStyle(style);
0144     style->deref();
0145     return true;
0146 }
0147 
0148 static bool execStyleChange(KHTMLPart *part, int propertyID, int propertyEnum)
0149 {
0150     CSSStyleDeclarationImpl *style = new CSSStyleDeclarationImpl(nullptr);
0151     style->setProperty(propertyID, propertyEnum);
0152     style->ref();
0153     part->editor()->applyStyle(style);
0154     style->deref();
0155     return true;
0156 }
0157 
0158 static bool execStyleChange(KHTMLPart *part, int propertyID, const char *propertyValue)
0159 {
0160     return execStyleChange(part, propertyID, DOMString(propertyValue));
0161 }
0162 
0163 static Editor::TriState stateStyle(KHTMLPart *part, int propertyID, const char *desiredValue)
0164 {
0165     CSSStyleDeclarationImpl *style = new CSSStyleDeclarationImpl(nullptr);
0166     style->setProperty(propertyID, desiredValue);
0167     style->ref();
0168     Editor::TriState state = part->editor()->selectionHasStyle(style);
0169     style->deref();
0170     return state;
0171 }
0172 
0173 static bool selectionStartHasStyle(KHTMLPart *part, int propertyID, const char *desiredValue)
0174 {
0175     CSSStyleDeclarationImpl *style = new CSSStyleDeclarationImpl(nullptr);
0176     style->setProperty(propertyID, desiredValue);
0177     style->ref();
0178     bool hasStyle = part->editor()->selectionStartHasStyle(style);
0179     style->deref();
0180     return hasStyle;
0181 }
0182 
0183 static DOMString valueStyle(KHTMLPart *part, int propertyID)
0184 {
0185     return part->editor()->selectionStartStylePropertyValue(propertyID);
0186 }
0187 
0188 // =============================================================================================
0189 //
0190 // execCommand implementations
0191 //
0192 
0193 static bool execBackColor(KHTMLPart *part, bool /*userInterface*/, const DOMString &value)
0194 {
0195     return execStyleChange(part, CSS_PROP_BACKGROUND_COLOR, value);
0196 }
0197 
0198 static bool execBold(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0199 {
0200     bool isBold = selectionStartHasStyle(part, CSS_PROP_FONT_WEIGHT, "bold");
0201     return execStyleChange(part, CSS_PROP_FONT_WEIGHT, isBold ? "normal" : "bold");
0202 }
0203 
0204 static bool execCopy(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0205 {
0206     part->editor()->copy();
0207     return true;
0208 }
0209 
0210 static bool execCut(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0211 {
0212     part->editor()->cut();
0213     return true;
0214 }
0215 
0216 static bool execDelete(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0217 {
0218     TypingCommandImpl::deleteKeyPressed0(KPAC::xmlDocImpl(part));
0219     return true;
0220 }
0221 
0222 static bool execFontName(KHTMLPart *part, bool /*userInterface*/, const DOMString &value)
0223 {
0224     return execStyleChange(part, CSS_PROP_FONT_FAMILY, value);
0225 }
0226 
0227 static bool execFontSize(KHTMLPart *part, bool /*userInterface*/, const DOMString &value)
0228 {
0229     // This should handle sizes 1-7 like <font> does. Who the heck designed this interface? (Rhetorical question)
0230     bool ok;
0231     int val = value.string().toInt(&ok);
0232     if (ok && val >= 1 && val <= 7) {
0233         int size;
0234         switch (val) {
0235         case 1: size = CSS_VAL_XX_SMALL; break;
0236         case 2: size = CSS_VAL_SMALL; break;
0237         case 3: size = CSS_VAL_MEDIUM; break;
0238         case 4: size = CSS_VAL_LARGE; break;
0239         case 5: size = CSS_VAL_X_LARGE;  break;
0240         case 6: size = CSS_VAL_XX_LARGE; break;
0241         default: size = CSS_VAL__KHTML_XXX_LARGE;
0242         }
0243         return execStyleChange(part, CSS_PROP_FONT_SIZE, size);
0244     }
0245 
0246     return execStyleChange(part, CSS_PROP_FONT_SIZE, value);
0247 }
0248 
0249 static bool execForeColor(KHTMLPart *part, bool /*userInterface*/, const DOMString &value)
0250 {
0251     return execStyleChange(part, CSS_PROP_COLOR, value);
0252 }
0253 
0254 static bool execIndent(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0255 {
0256     part->editor()->indent();
0257     return true;
0258 }
0259 
0260 static bool execInsertNewline(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0261 {
0262     TypingCommandImpl::insertNewline0(KPAC::xmlDocImpl(part));
0263     return true;
0264 }
0265 
0266 static bool execInsertParagraph(KHTMLPart * /*part*/, bool /*userInterface*/, const DOMString &/*value*/)
0267 {
0268     // FIXME: Implement.
0269     return false;
0270 }
0271 
0272 static bool execInsertText(KHTMLPart *part, bool /*userInterface*/, const DOMString &value)
0273 {
0274     TypingCommandImpl::insertText0(KPAC::xmlDocImpl(part), value);
0275     return true;
0276 }
0277 
0278 static bool execInsertOrderedList(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0279 {
0280     InsertListCommandImpl::insertList(KPAC::xmlDocImpl(part), InsertListCommandImpl::OrderedList);
0281     return true;
0282 }
0283 
0284 static bool execInsertUnorderedList(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0285 {
0286     InsertListCommandImpl::insertList(KPAC::xmlDocImpl(part), InsertListCommandImpl::UnorderedList);
0287     return true;
0288 }
0289 
0290 static bool execItalic(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0291 {
0292     bool isItalic = selectionStartHasStyle(part, CSS_PROP_FONT_STYLE, "italic");
0293     return execStyleChange(part, CSS_PROP_FONT_STYLE, isItalic ? "normal" : "italic");
0294 }
0295 
0296 static bool execJustifyCenter(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0297 {
0298     return execStyleChange(part, CSS_PROP_TEXT_ALIGN, "center");
0299 }
0300 
0301 static bool execJustifyFull(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0302 {
0303     return execStyleChange(part, CSS_PROP_TEXT_ALIGN, "justify");
0304 }
0305 
0306 static bool execJustifyLeft(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0307 {
0308     return execStyleChange(part, CSS_PROP_TEXT_ALIGN, "left");
0309 }
0310 
0311 static bool execJustifyRight(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0312 {
0313     return execStyleChange(part, CSS_PROP_TEXT_ALIGN, "right");
0314 }
0315 
0316 static bool execOutdent(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0317 {
0318     part->editor()->outdent();
0319     return true;
0320 }
0321 
0322 #ifndef NO_SUPPORT_PASTE
0323 
0324 static bool execPaste(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0325 {
0326     part->editor()->paste();
0327     return true;
0328 }
0329 
0330 #endif
0331 
0332 static bool execPrint(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0333 {
0334     part->editor()->print();
0335     return true;
0336 }
0337 
0338 static bool execRedo(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0339 {
0340     part->editor()->redo();
0341     return true;
0342 }
0343 
0344 static bool execSelectAll(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0345 {
0346     part->selectAll();
0347     return true;
0348 }
0349 
0350 static bool execStrikeThrough(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0351 {
0352     bool isStriked = selectionStartHasStyle(part, CSS_PROP_TEXT_DECORATION, "line-through");
0353     return execStyleChange(part, CSS_PROP_TEXT_DECORATION, isStriked ? "none" : "line-through");
0354 }
0355 
0356 static bool execSubscript(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0357 {
0358     return execStyleChange(part, CSS_PROP_VERTICAL_ALIGN, "sub");
0359 }
0360 
0361 static bool execSuperscript(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0362 {
0363     return execStyleChange(part, CSS_PROP_VERTICAL_ALIGN, "super");
0364 }
0365 
0366 static bool execUndo(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0367 {
0368     part->editor()->undo();
0369     return true;
0370 }
0371 
0372 static bool execUnderline(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0373 {
0374     bool isUnderline = selectionStartHasStyle(part, CSS_PROP_TEXT_DECORATION, "underline");
0375     return execStyleChange(part, CSS_PROP_TEXT_DECORATION, isUnderline ? "none" : "underline");
0376 }
0377 
0378 static bool execUnselect(KHTMLPart *part, bool /*userInterface*/, const DOMString &/*value*/)
0379 {
0380     KPAC::clearSelection(part);
0381     return true;
0382 }
0383 
0384 // =============================================================================================
0385 //
0386 // queryCommandEnabled implementations
0387 //
0388 // It's a bit difficult to get a clear notion of the difference between
0389 // "supported" and "enabled" from reading the Microsoft documentation, but
0390 // what little I could glean from that seems to make some sense.
0391 //     Supported = The command is supported by this object.
0392 //     Enabled =   The command is available and enabled.
0393 
0394 static bool enabled(KHTMLPart * /*part*/)
0395 {
0396     return true;
0397 }
0398 
0399 static bool enabledAnySelection(KHTMLPart *part)
0400 {
0401     return KPAC::caret(part).notEmpty();
0402 }
0403 
0404 #ifndef NO_SUPPORT_PASTE
0405 
0406 static bool enabledPaste(KHTMLPart *part)
0407 {
0408     return part->editor()->canPaste();
0409 }
0410 
0411 #endif
0412 
0413 static bool enabledRangeSelection(KHTMLPart *part)
0414 {
0415     return KPAC::caret(part).state() == Selection::RANGE;
0416 }
0417 
0418 static bool enabledRedo(KHTMLPart *part)
0419 {
0420     return part->editor()->canRedo();
0421 }
0422 
0423 static bool enabledUndo(KHTMLPart *part)
0424 {
0425     return part->editor()->canUndo();
0426 }
0427 
0428 // =============================================================================================
0429 //
0430 // queryCommandIndeterm/State implementations
0431 //
0432 // It's a bit difficult to get a clear notion of what these methods are supposed
0433 // to do from reading the Microsoft documentation, but my current guess is this:
0434 //
0435 //     queryCommandState and queryCommandIndeterm work in concert to return
0436 //     the two bits of information that are needed to tell, for instance,
0437 //     if the text of a selection is bold. The answer can be "yes", "no", or
0438 //     "partially".
0439 //
0440 // If this is so, then queryCommandState should return "yes" in the case where
0441 // all the text is bold and "no" for non-bold or partially-bold text.
0442 // Then, queryCommandIndeterm should return "no" in the case where
0443 // all the text is either all bold or not-bold and and "yes" for partially-bold text.
0444 
0445 static Editor::TriState stateNone(KHTMLPart * /*part*/)
0446 {
0447     return Editor::FalseTriState;
0448 }
0449 
0450 static Editor::TriState stateBold(KHTMLPart *part)
0451 {
0452     return stateStyle(part, CSS_PROP_FONT_WEIGHT, "bold");
0453 }
0454 
0455 static Editor::TriState stateItalic(KHTMLPart *part)
0456 {
0457     return stateStyle(part, CSS_PROP_FONT_STYLE, "italic");
0458 }
0459 
0460 static Editor::TriState stateStrike(KHTMLPart *part)
0461 {
0462     return stateStyle(part, CSS_PROP_TEXT_DECORATION, "line-through");
0463 }
0464 
0465 static Editor::TriState stateSubscript(KHTMLPart *part)
0466 {
0467     return stateStyle(part, CSS_PROP_VERTICAL_ALIGN, "sub");
0468 }
0469 
0470 static Editor::TriState stateSuperscript(KHTMLPart *part)
0471 {
0472     return stateStyle(part, CSS_PROP_VERTICAL_ALIGN, "super");
0473 }
0474 
0475 static Editor::TriState stateUnderline(KHTMLPart *part)
0476 {
0477     return stateStyle(part, CSS_PROP_TEXT_DECORATION, "underline");
0478 }
0479 
0480 // =============================================================================================
0481 //
0482 // queryCommandValue implementations
0483 //
0484 
0485 static DOMString valueNull(KHTMLPart * /*part*/)
0486 {
0487     return DOMString();
0488 }
0489 
0490 static DOMString valueBackColor(KHTMLPart *part)
0491 {
0492     return valueStyle(part, CSS_PROP_BACKGROUND_COLOR);
0493 }
0494 
0495 static DOMString valueFontName(KHTMLPart *part)
0496 {
0497     return valueStyle(part, CSS_PROP_FONT_FAMILY);
0498 }
0499 
0500 static DOMString valueFontSize(KHTMLPart *part)
0501 {
0502     return valueStyle(part, CSS_PROP_FONT_SIZE);
0503 }
0504 
0505 static DOMString valueForeColor(KHTMLPart *part)
0506 {
0507     return valueStyle(part, CSS_PROP_COLOR);
0508 }
0509 
0510 // =============================================================================================
0511 
0512 struct EditorCommandInfo {
0513     const char *name;
0514     CommandImp imp;
0515 };
0516 
0517 // NOTE: strictly keep in sync with EditorCommand in editor_command.h
0518 static const EditorCommandInfo commands[] = {
0519 
0520     { "backColor", { execBackColor, enabled, stateNone, valueBackColor } },
0521     { "bold", { execBold, enabledAnySelection, stateBold, valueNull } },
0522     { "copy", { execCopy, enabledRangeSelection, stateNone, valueNull } },
0523     { "cut", { execCut, enabledRangeSelection, stateNone, valueNull } },
0524     { "delete", { execDelete, enabledAnySelection, stateNone, valueNull } },
0525     { "fontName", { execFontName, enabledAnySelection, stateNone, valueFontName } },
0526     { "fontSize", { execFontSize, enabledAnySelection, stateNone, valueFontSize } },
0527     { "foreColor", { execForeColor, enabledAnySelection, stateNone, valueForeColor } },
0528     { "indent", { execIndent, enabledAnySelection, stateNone, valueNull } },
0529     { "insertNewline", { execInsertNewline, enabledAnySelection, stateNone, valueNull } },
0530     { "insertOrderedList", { execInsertOrderedList, enabledAnySelection, stateNone, valueNull } },
0531     { "insertParagraph", { execInsertParagraph, enabledAnySelection, stateNone, valueNull } },
0532     { "insertText", { execInsertText, enabledAnySelection, stateNone, valueNull } },
0533     { "insertUnorderedList", { execInsertUnorderedList, enabledAnySelection, stateNone, valueNull } },
0534     { "italic", { execItalic, enabledAnySelection, stateItalic, valueNull } },
0535     { "justifyCenter", { execJustifyCenter, enabledAnySelection, stateNone, valueNull } },
0536     { "justifyFull", { execJustifyFull, enabledAnySelection, stateNone, valueNull } },
0537     { "justifyLeft", { execJustifyLeft, enabledAnySelection, stateNone, valueNull } },
0538     { "justifyNone", { execJustifyLeft, enabledAnySelection, stateNone, valueNull } },
0539     { "justifyRight", { execJustifyRight, enabledAnySelection, stateNone, valueNull } },
0540     { "outdent", { execOutdent, enabledAnySelection, stateNone, valueNull } },
0541 #ifndef NO_SUPPORT_PASTE
0542     { "paste", { execPaste, enabledPaste, stateNone, valueNull } },
0543 #else
0544     { 0, { 0, 0, 0, 0 } },
0545 #endif
0546     { "print", { execPrint, enabled, stateNone, valueNull } },
0547     { "redo", { execRedo, enabledRedo, stateNone, valueNull } },
0548     { "selectAll", { execSelectAll, enabled, stateNone, valueNull } },
0549     { "StrikeThrough", {execStrikeThrough, enabled, stateStrike, valueNull } },
0550     { "subscript", { execSubscript, enabledAnySelection, stateSubscript, valueNull } },
0551     { "superscript", { execSuperscript, enabledAnySelection, stateSuperscript, valueNull } },
0552     { "underline", { execUnderline, enabledAnySelection, stateUnderline, valueNull } },
0553     { "undo", { execUndo, enabledUndo, stateNone, valueNull } },
0554     { "unselect", { execUnselect, enabledAnySelection, stateNone, valueNull } }
0555 
0556     //
0557     // The "unsupported" commands are listed here since they appear in the Microsoft
0558     // documentation used as the basis for the list.
0559     //
0560 
0561     // 2d-position (not supported)
0562     // absolutePosition (not supported)
0563     // blockDirLTR (not supported)
0564     // blockDirRTL (not supported)
0565     // browseMode (not supported)
0566     // clearAuthenticationCache (not supported)
0567     // createBookmark (not supported)
0568     // createLink (not supported)
0569     // dirLTR (not supported)
0570     // dirRTL (not supported)
0571     // editMode (not supported)
0572     // formatBlock (not supported)
0573     // inlineDirLTR (not supported)
0574     // inlineDirRTL (not supported)
0575     // insertButton (not supported)
0576     // insertFieldSet (not supported)
0577     // insertHorizontalRule (not supported)
0578     // insertIFrame (not supported)
0579     // insertImage (not supported)
0580     // insertInputButton (not supported)
0581     // insertInputCheckbox (not supported)
0582     // insertInputFileUpload (not supported)
0583     // insertInputHidden (not supported)
0584     // insertInputImage (not supported)
0585     // insertInputPassword (not supported)
0586     // insertInputRadio (not supported)
0587     // insertInputReset (not supported)
0588     // insertInputSubmit (not supported)
0589     // insertInputText (not supported)
0590     // insertMarquee (not supported)
0591     // insertOrderedList (not supported)
0592     // insertSelectDropDown (not supported)
0593     // insertSelectListBox (not supported)
0594     // insertTextArea (not supported)
0595     // insertUnorderedList (not supported)
0596     // liveResize (not supported)
0597     // multipleSelection (not supported)
0598     // open (not supported)
0599     // overwrite (not supported)
0600     // playImage (not supported)
0601     // refresh (not supported)
0602     // removeFormat (not supported)
0603     // removeParaFormat (not supported)
0604     // saveAs (not supported)
0605     // sizeToControl (not supported)
0606     // sizeToControlHeight (not supported)
0607     // sizeToControlWidth (not supported)
0608     // stop (not supported)
0609     // stopimage (not supported)
0610     // strikethrough (not supported)
0611     // unbookmark (not supported)
0612     // underline (not supported)
0613     // unlink (not supported)
0614 };
0615 
0616 static CommandDict createCommandDictionary()
0617 {
0618     const int numCommands = sizeof(commands) / sizeof(commands[0]);
0619     CommandDict commandDictionary; // case-insensitive dictionary
0620     for (int i = 0; i < numCommands; ++i) {
0621         if (commands[i].name) {
0622             commandDictionary.insert(QString(commands[i].name).toLower(), &commands[i].imp);
0623         }
0624     }
0625     return commandDictionary;
0626 }
0627 
0628 const CommandImp *JSEditor::commandImp(const DOMString &command)
0629 {
0630     static CommandDict commandDictionary = createCommandDictionary();
0631     const CommandImp *result = commandDictionary.value(command.string().toLower());
0632 #ifdef DEBUG_COMMANDS
0633     if (!result) {
0634         qCDebug(KHTML_LOG) << "[Command is not supported yet]" << command;
0635     }
0636 #endif
0637     return result;
0638 }
0639 
0640 const CommandImp *JSEditor::commandImp(int command)
0641 {
0642     if (command < 0 || command >= int(sizeof commands / sizeof commands[0])) {
0643         return nullptr;
0644     }
0645     return &commands[command].imp;
0646 }
0647 
0648 } // namespace DOM
0649 
0650 #undef KPAC