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