00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "jsediting.h"
00027 #include "htmlediting.h"
00028 #include "editor.h"
00029
00030 #include "css/cssproperties.h"
00031 #include "css/css_valueimpl.h"
00032 #include "xml/dom_selection.h"
00033 #include "xml/dom_docimpl.h"
00034 #include "dom/dom_string.h"
00035
00036 #include "misc/khtml_partaccessor.h"
00037
00038 #include <QHash>
00039 #include <QString>
00040
00041 using khtml::TypingCommand;
00042
00043 #define KPAC khtml::KHTMLPartAccessor
00044
00045 namespace DOM {
00046
00047 class DocumentImpl;
00048
00049 struct CommandImp {
00050 bool (*execFn)(KHTMLPart *part, bool userInterface, const DOMString &value);
00051 bool (*enabledFn)(KHTMLPart *part);
00052 Editor::TriState (*stateFn)(KHTMLPart *part);
00053 DOMString (*valueFn)(KHTMLPart *part);
00054 };
00055
00056 typedef QHash<QString,const CommandImp*> CommandDict;
00057 static CommandDict createCommandDictionary();
00058
00059 bool JSEditor::execCommand(const CommandImp *cmd, bool userInterface, const DOMString &value)
00060 {
00061 if (!cmd || !cmd->enabledFn)
00062 return false;
00063 KHTMLPart *part = m_doc->part();
00064 if (!part)
00065 return false;
00066 m_doc->updateLayout();
00067 return cmd->enabledFn(part) && cmd->execFn(part, userInterface, value);
00068 }
00069
00070 bool JSEditor::queryCommandEnabled(const CommandImp *cmd)
00071 {
00072 if (!cmd || !cmd->enabledFn)
00073 return false;
00074 KHTMLPart *part = m_doc->part();
00075 if (!part)
00076 return false;
00077 m_doc->updateLayout();
00078 return cmd->enabledFn(part);
00079 }
00080
00081 bool JSEditor::queryCommandIndeterm(const CommandImp *cmd)
00082 {
00083 if (!cmd || !cmd->enabledFn)
00084 return false;
00085 KHTMLPart *part = m_doc->part();
00086 if (!part)
00087 return false;
00088 m_doc->updateLayout();
00089 return cmd->stateFn(part) == Editor::MixedTriState;
00090 }
00091
00092 bool JSEditor::queryCommandState(const CommandImp *cmd)
00093 {
00094 if (!cmd || !cmd->enabledFn)
00095 return false;
00096 KHTMLPart *part = m_doc->part();
00097 if (!part)
00098 return false;
00099 m_doc->updateLayout();
00100 return cmd->stateFn(part) != Editor::FalseTriState;
00101 }
00102
00103 bool JSEditor::queryCommandSupported(const CommandImp *cmd)
00104 {
00105 return cmd != 0;
00106 }
00107
00108 DOMString JSEditor::queryCommandValue(const CommandImp *cmd)
00109 {
00110 if (!cmd || !cmd->enabledFn)
00111 return DOMString();
00112 KHTMLPart *part = m_doc->part();
00113 if (!part)
00114 return DOMString();
00115 m_doc->updateLayout();
00116 return cmd->valueFn(part);
00117 }
00118
00119
00120
00121
00122
00123 static bool execStyleChange(KHTMLPart *part, int propertyID, const DOMString &propertyValue)
00124 {
00125 CSSStyleDeclarationImpl *style = new CSSStyleDeclarationImpl(0);
00126 style->setProperty(propertyID, propertyValue);
00127 style->ref();
00128 part->editor()->applyStyle(style);
00129 style->deref();
00130 return true;
00131 }
00132
00133 static bool execStyleChange(KHTMLPart *part, int propertyID, const char *propertyValue)
00134 {
00135 return execStyleChange(part, propertyID, DOMString(propertyValue));
00136 }
00137
00138 static Editor::TriState stateStyle(KHTMLPart *part, int propertyID, const char *desiredValue)
00139 {
00140 CSSStyleDeclarationImpl *style = new CSSStyleDeclarationImpl(0);
00141 style->setProperty(propertyID, desiredValue);
00142 style->ref();
00143 Editor::TriState state = part->editor()->selectionHasStyle(style);
00144 style->deref();
00145 return state;
00146 }
00147
00148 static bool selectionStartHasStyle(KHTMLPart *part, int propertyID, const char *desiredValue)
00149 {
00150 CSSStyleDeclarationImpl *style = new CSSStyleDeclarationImpl(0);
00151 style->setProperty(propertyID, desiredValue);
00152 style->ref();
00153 bool hasStyle = part->editor()->selectionStartHasStyle(style);
00154 style->deref();
00155 return hasStyle;
00156 }
00157
00158 static DOMString valueStyle(KHTMLPart *part, int propertyID)
00159 {
00160 return part->editor()->selectionStartStylePropertyValue(propertyID);
00161 }
00162
00163
00164
00165
00166
00167
00168 static bool execBackColor(KHTMLPart *part, bool , const DOMString &value)
00169 {
00170 return execStyleChange(part, CSS_PROP_BACKGROUND_COLOR, value);
00171 }
00172
00173 static bool execBold(KHTMLPart *part, bool , const DOMString &)
00174 {
00175 bool isBold = selectionStartHasStyle(part, CSS_PROP_FONT_WEIGHT, "bold");
00176 return execStyleChange(part, CSS_PROP_FONT_WEIGHT, isBold ? "normal" : "bold");
00177 }
00178
00179 static bool execCopy(KHTMLPart *part, bool , const DOMString &)
00180 {
00181 part->editor()->copy();
00182 return true;
00183 }
00184
00185 static bool execCut(KHTMLPart *part, bool , const DOMString &)
00186 {
00187 part->editor()->cut();
00188 return true;
00189 }
00190
00191 static bool execDelete(KHTMLPart *part, bool , const DOMString &)
00192 {
00193 TypingCommand::deleteKeyPressed(KPAC::xmlDocImpl(part));
00194 return true;
00195 }
00196
00197 static bool execFontName(KHTMLPart *part, bool , const DOMString &value)
00198 {
00199 return execStyleChange(part, CSS_PROP_FONT_FAMILY, value);
00200 }
00201
00202 static bool execFontSize(KHTMLPart *part, bool , const DOMString &value)
00203 {
00204 return execStyleChange(part, CSS_PROP_FONT_SIZE, value);
00205 }
00206
00207 static bool execForeColor(KHTMLPart *part, bool , const DOMString &value)
00208 {
00209 return execStyleChange(part, CSS_PROP_COLOR, value);
00210 }
00211
00212 static bool execIndent(KHTMLPart * , bool , const DOMString &)
00213 {
00214
00215 return false;
00216 }
00217
00218 static bool execInsertNewline(KHTMLPart *part, bool , const DOMString &)
00219 {
00220 TypingCommand::insertNewline(KPAC::xmlDocImpl(part));
00221 return true;
00222 }
00223
00224 static bool execInsertParagraph(KHTMLPart * , bool , const DOMString &)
00225 {
00226
00227 return false;
00228 }
00229
00230 static bool execInsertText(KHTMLPart *part, bool , const DOMString &value)
00231 {
00232 TypingCommand::insertText(KPAC::xmlDocImpl(part), value);
00233 return true;
00234 }
00235
00236 static bool execItalic(KHTMLPart *part, bool , const DOMString &)
00237 {
00238 bool isItalic = selectionStartHasStyle(part, CSS_PROP_FONT_STYLE, "italic");
00239 return execStyleChange(part, CSS_PROP_FONT_STYLE, isItalic ? "normal" : "italic");
00240 }
00241
00242 static bool execJustifyCenter(KHTMLPart *part, bool , const DOMString &)
00243 {
00244 return execStyleChange(part, CSS_PROP_TEXT_ALIGN, "center");
00245 }
00246
00247 static bool execJustifyFull(KHTMLPart *part, bool , const DOMString &)
00248 {
00249 return execStyleChange(part, CSS_PROP_TEXT_ALIGN, "justify");
00250 }
00251
00252 static bool execJustifyLeft(KHTMLPart *part, bool , const DOMString &)
00253 {
00254 return execStyleChange(part, CSS_PROP_TEXT_ALIGN, "left");
00255 }
00256
00257 static bool execJustifyRight(KHTMLPart *part, bool , const DOMString &)
00258 {
00259 return execStyleChange(part, CSS_PROP_TEXT_ALIGN, "right");
00260 }
00261
00262 static bool execOutdent(KHTMLPart * , bool , const DOMString &)
00263 {
00264
00265 return false;
00266 }
00267
00268 #ifndef NO_SUPPORT_PASTE
00269
00270 static bool execPaste(KHTMLPart *part, bool , const DOMString &)
00271 {
00272 part->editor()->paste();
00273 return true;
00274 }
00275
00276 #endif
00277
00278 static bool execPrint(KHTMLPart *part, bool , const DOMString &)
00279 {
00280 part->editor()->print();
00281 return true;
00282 }
00283
00284 static bool execRedo(KHTMLPart *part, bool , const DOMString &)
00285 {
00286 part->editor()->redo();
00287 return true;
00288 }
00289
00290 static bool execSelectAll(KHTMLPart *part, bool , const DOMString &)
00291 {
00292 part->selectAll();
00293 return true;
00294 }
00295
00296 static bool execSubscript(KHTMLPart *part, bool , const DOMString &)
00297 {
00298 return execStyleChange(part, CSS_PROP_VERTICAL_ALIGN, "sub");
00299 }
00300
00301 static bool execSuperscript(KHTMLPart *part, bool , const DOMString &)
00302 {
00303 return execStyleChange(part, CSS_PROP_VERTICAL_ALIGN, "super");
00304 }
00305
00306 static bool execUndo(KHTMLPart *part, bool , const DOMString &)
00307 {
00308 part->editor()->undo();
00309 return true;
00310 }
00311
00312 static bool execUnselect(KHTMLPart *part, bool , const DOMString &)
00313 {
00314 KPAC::clearSelection(part);
00315 return true;
00316 }
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328 static bool enabled(KHTMLPart * )
00329 {
00330 return true;
00331 }
00332
00333 static bool enabledAnySelection(KHTMLPart *part)
00334 {
00335 return KPAC::caret(part).notEmpty();
00336 }
00337
00338 #ifndef NO_SUPPORT_PASTE
00339
00340 static bool enabledPaste(KHTMLPart *part)
00341 {
00342 return part->editor()->canPaste();
00343 }
00344
00345 #endif
00346
00347 static bool enabledRangeSelection(KHTMLPart *part)
00348 {
00349 return KPAC::caret(part).state() == Selection::RANGE;
00350 }
00351
00352 static bool enabledRedo(KHTMLPart *part)
00353 {
00354 return part->editor()->canRedo();
00355 }
00356
00357 static bool enabledUndo(KHTMLPart *part)
00358 {
00359 return part->editor()->canUndo();
00360 }
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379 static Editor::TriState stateNone(KHTMLPart * )
00380 {
00381 return Editor::FalseTriState;
00382 }
00383
00384 static Editor::TriState stateBold(KHTMLPart *part)
00385 {
00386 return stateStyle(part, CSS_PROP_FONT_WEIGHT, "bold");
00387 }
00388
00389 static Editor::TriState stateItalic(KHTMLPart *part)
00390 {
00391 return stateStyle(part, CSS_PROP_FONT_STYLE, "italic");
00392 }
00393
00394 static Editor::TriState stateSubscript(KHTMLPart *part)
00395 {
00396 return stateStyle(part, CSS_PROP_VERTICAL_ALIGN, "sub");
00397 }
00398
00399 static Editor::TriState stateSuperscript(KHTMLPart *part)
00400 {
00401 return stateStyle(part, CSS_PROP_VERTICAL_ALIGN, "super");
00402 }
00403
00404
00405
00406
00407
00408
00409 static DOMString valueNull(KHTMLPart * )
00410 {
00411 return DOMString();
00412 }
00413
00414 static DOMString valueBackColor(KHTMLPart *part)
00415 {
00416 return valueStyle(part, CSS_PROP_BACKGROUND_COLOR);
00417 }
00418
00419 static DOMString valueFontName(KHTMLPart *part)
00420 {
00421 return valueStyle(part, CSS_PROP_FONT_FAMILY);
00422 }
00423
00424 static DOMString valueFontSize(KHTMLPart *part)
00425 {
00426 return valueStyle(part, CSS_PROP_FONT_SIZE);
00427 }
00428
00429 static DOMString valueForeColor(KHTMLPart *part)
00430 {
00431 return valueStyle(part, CSS_PROP_COLOR);
00432 }
00433
00434
00435
00436 struct EditorCommandInfo { const char *name; CommandImp imp; };
00437
00438
00439 static const EditorCommandInfo commands[] = {
00440
00441 { "backColor", { execBackColor, enabled, stateNone, valueBackColor } },
00442 { "bold", { execBold, enabledAnySelection, stateBold, valueNull } },
00443 { "copy", { execCopy, enabledRangeSelection, stateNone, valueNull } },
00444 { "cut", { execCut, enabledRangeSelection, stateNone, valueNull } },
00445 { "delete", { execDelete, enabledAnySelection, stateNone, valueNull } },
00446 { "fontName", { execFontName, enabledAnySelection, stateNone, valueFontName } },
00447 { "fontSize", { execFontSize, enabledAnySelection, stateNone, valueFontSize } },
00448 { "foreColor", { execForeColor, enabledAnySelection, stateNone, valueForeColor } },
00449 { "indent", { execIndent, enabledAnySelection, stateNone, valueNull } },
00450 { "insertNewline", { execInsertNewline, enabledAnySelection, stateNone, valueNull } },
00451 { "insertParagraph", { execInsertParagraph, enabledAnySelection, stateNone, valueNull } },
00452 { "insertText", { execInsertText, enabledAnySelection, stateNone, valueNull } },
00453 { "italic", { execItalic, enabledAnySelection, stateItalic, valueNull } },
00454 { "justifyCenter", { execJustifyCenter, enabledAnySelection, stateNone, valueNull } },
00455 { "justifyFull", { execJustifyFull, enabledAnySelection, stateNone, valueNull } },
00456 { "justifyLeft", { execJustifyLeft, enabledAnySelection, stateNone, valueNull } },
00457 { "justifyNone", { execJustifyLeft, enabledAnySelection, stateNone, valueNull } },
00458 { "justifyRight", { execJustifyRight, enabledAnySelection, stateNone, valueNull } },
00459 { "outdent", { execOutdent, enabledAnySelection, stateNone, valueNull } },
00460 #ifndef NO_SUPPORT_PASTE
00461 { "paste", { execPaste, enabledPaste, stateNone, valueNull } },
00462 #else
00463 { 0, { 0, 0, 0, 0 } },
00464 #endif
00465 { "print", { execPrint, enabled, stateNone, valueNull } },
00466 { "redo", { execRedo, enabledRedo, stateNone, valueNull } },
00467 { "selectAll", { execSelectAll, enabled, stateNone, valueNull } },
00468 { "subscript", { execSubscript, enabledAnySelection, stateSubscript, valueNull } },
00469 { "superscript", { execSuperscript, enabledAnySelection, stateSuperscript, valueNull } },
00470 { "undo", { execUndo, enabledUndo, stateNone, valueNull } },
00471 { "unselect", { execUnselect, enabledAnySelection, stateNone, valueNull } }
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531 };
00532
00533 static CommandDict createCommandDictionary()
00534 {
00535 const int numCommands = sizeof(commands) / sizeof(commands[0]);
00536 CommandDict commandDictionary;
00537 for (int i = 0; i < numCommands; ++i) {
00538 if (commands[i].name)
00539 commandDictionary.insert(QString(commands[i].name).toLower(), &commands[i].imp);
00540 }
00541 return commandDictionary;
00542 }
00543
00544 const CommandImp *JSEditor::commandImp(const DOMString &command)
00545 {
00546 static CommandDict commandDictionary = createCommandDictionary();
00547 CommandDict::const_iterator it = commandDictionary.find(command.string().toLower());
00548 return commandDictionary.value( command.string().toLower() );
00549 }
00550
00551 const CommandImp *JSEditor::commandImp(int command)
00552 {
00553 if (command < 0 || command > int(sizeof commands / sizeof commands[0]))
00554 return 0;
00555 return &commands[command].imp;
00556 }
00557
00558
00559
00560 }
00561
00562 #undef KPAC