#include "jsediting.h"
#include "cssproperties.h"
#include "htmlediting.h"
#include "khtml_part.h"
#include "qstring.h"
#include "selection.h"
#if APPLE_CHANGES
#include "KWQKHTMLPart.h"
#endif
using khtml::TypingCommand;
namespace DOM {
class DocumentImpl;
namespace {
bool supportsPasteCommand = false;
struct CommandImp {
bool (*execFn)(KHTMLPart *part, bool userInterface, const DOMString &value);
bool (*enabledFn)(KHTMLPart *part);
KHTMLPart::TriState (*stateFn)(KHTMLPart *part);
DOMString (*valueFn)(KHTMLPart *part);
};
QDict<CommandImp> createCommandDictionary();
const CommandImp *commandImp(const DOMString &command)
{
static QDict<CommandImp> commandDictionary = createCommandDictionary();
return commandDictionary.find(command.string());
}
}
bool JSEditor::execCommand(const DOMString &command, bool userInterface, const DOMString &value)
{
const CommandImp *cmd = commandImp(command);
if (!cmd)
return false;
KHTMLPart *part = m_doc->part();
if (!part)
return false;
m_doc->updateLayout();
return cmd->enabledFn(part) && cmd->execFn(part, userInterface, value);
}
bool JSEditor::queryCommandEnabled(const DOMString &command)
{
const CommandImp *cmd = commandImp(command);
if (!cmd)
return false;
KHTMLPart *part = m_doc->part();
if (!part)
return false;
m_doc->updateLayout();
return cmd->enabledFn(part);
}
bool JSEditor::queryCommandIndeterm(const DOMString &command)
{
const CommandImp *cmd = commandImp(command);
if (!cmd)
return false;
KHTMLPart *part = m_doc->part();
if (!part)
return false;
m_doc->updateLayout();
return cmd->stateFn(part) == KHTMLPart::mixedTriState;
}
bool JSEditor::queryCommandState(const DOMString &command)
{
const CommandImp *cmd = commandImp(command);
if (!cmd)
return false;
KHTMLPart *part = m_doc->part();
if (!part)
return false;
m_doc->updateLayout();
return cmd->stateFn(part) != KHTMLPart::falseTriState;
}
bool JSEditor::queryCommandSupported(const DOMString &command)
{
if (!supportsPasteCommand && command.string().lower() == "paste")
return false;
return commandImp(command) != 0;
}
DOMString JSEditor::queryCommandValue(const DOMString &command)
{
const CommandImp *cmd = commandImp(command);
if (!cmd)
return DOMString();
KHTMLPart *part = m_doc->part();
if (!part)
return DOMString();
m_doc->updateLayout();
return cmd->valueFn(part);
}
void JSEditor::setSupportsPasteCommand(bool flag)
{
supportsPasteCommand = flag;
}
namespace {
bool execStyleChange(KHTMLPart *part, int propertyID, const DOMString &propertyValue)
{
CSSMutableStyleDeclarationImpl *style = new CSSMutableStyleDeclarationImpl;
style->setProperty(propertyID, propertyValue);
style->ref();
part->applyStyle(style);
style->deref();
return true;
}
bool execStyleChange(KHTMLPart *part, int propertyID, const char *propertyValue)
{
return execStyleChange(part, propertyID, DOMString(propertyValue));
}
KHTMLPart::TriState stateStyle(KHTMLPart *part, int propertyID, const char *desiredValue)
{
CSSMutableStyleDeclarationImpl *style = new CSSMutableStyleDeclarationImpl;
style->setProperty(propertyID, desiredValue);
style->ref();
KHTMLPart::TriState state = part->selectionHasStyle(style);
style->deref();
return state;
}
bool selectionStartHasStyle(KHTMLPart *part, int propertyID, const char *desiredValue)
{
CSSMutableStyleDeclarationImpl *style = new CSSMutableStyleDeclarationImpl;
style->setProperty(propertyID, desiredValue);
style->ref();
bool hasStyle = part->selectionStartHasStyle(style);
style->deref();
return hasStyle;
}
DOMString valueStyle(KHTMLPart *part, int propertyID)
{
return part->selectionStartStylePropertyValue(propertyID);
}
bool execBackColor(KHTMLPart *part, bool userInterface, const DOMString &value)
{
return execStyleChange(part, CSS_PROP_BACKGROUND_COLOR, value);
}
bool execBold(KHTMLPart *part, bool userInterface, const DOMString &value)
{
bool isBold = selectionStartHasStyle(part, CSS_PROP_FONT_WEIGHT, "bold");
return execStyleChange(part, CSS_PROP_FONT_WEIGHT, isBold ? "normal" : "bold");
}
bool execCopy(KHTMLPart *part, bool userInterface, const DOMString &value)
{
part->copyToPasteboard();
return true;
}
bool execCut(KHTMLPart *part, bool userInterface, const DOMString &value)
{
part->cutToPasteboard();
return true;
}
bool execDelete(KHTMLPart *part, bool userInterface, const DOMString &value)
{
TypingCommand::deleteKeyPressed(part->xmlDocImpl(), part->selectionGranularity() == khtml::WORD);
return true;
}
bool execForwardDelete(KHTMLPart *part, bool userInterface, const DOMString &value)
{
TypingCommand::forwardDeleteKeyPressed(part->xmlDocImpl());
return true;
}
bool execFontName(KHTMLPart *part, bool userInterface, const DOMString &value)
{
return execStyleChange(part, CSS_PROP_FONT_FAMILY, value);
}
bool execFontSize(KHTMLPart *part, bool userInterface, const DOMString &value)
{
return execStyleChange(part, CSS_PROP_FONT_SIZE, value);
}
bool execFontSizeDelta(KHTMLPart *part, bool userInterface, const DOMString &value)
{
return execStyleChange(part, CSS_PROP__KHTML_FONT_SIZE_DELTA, value);
}
bool execForeColor(KHTMLPart *part, bool userInterface, const DOMString &value)
{
return execStyleChange(part, CSS_PROP_COLOR, value);
}
bool execIndent(KHTMLPart *part, bool userInterface, const DOMString &value)
{
return false;
}
bool execInsertLineBreak(KHTMLPart *part, bool userInterface, const DOMString &value)
{
TypingCommand::insertLineBreak(part->xmlDocImpl());
return true;
}
bool execInsertParagraph(KHTMLPart *part, bool userInterface, const DOMString &value)
{
TypingCommand::insertParagraphSeparator(part->xmlDocImpl());
return true;
}
bool execInsertText(KHTMLPart *part, bool userInterface, const DOMString &value)
{
TypingCommand::insertText(part->xmlDocImpl(), value);
return true;
}
bool execItalic(KHTMLPart *part, bool userInterface, const DOMString &value)
{
bool isItalic = selectionStartHasStyle(part, CSS_PROP_FONT_STYLE, "italic");
return execStyleChange(part, CSS_PROP_FONT_STYLE, isItalic ? "normal" : "italic");
}
bool execJustifyCenter(KHTMLPart *part, bool userInterface, const DOMString &value)
{
return execStyleChange(part, CSS_PROP_TEXT_ALIGN, "center");
}
bool execJustifyFull(KHTMLPart *part, bool userInterface, const DOMString &value)
{
return execStyleChange(part, CSS_PROP_TEXT_ALIGN, "justify");
}
bool execJustifyLeft(KHTMLPart *part, bool userInterface, const DOMString &value)
{
return execStyleChange(part, CSS_PROP_TEXT_ALIGN, "left");
}
bool execJustifyRight(KHTMLPart *part, bool userInterface, const DOMString &value)
{
return execStyleChange(part, CSS_PROP_TEXT_ALIGN, "right");
}
bool execOutdent(KHTMLPart *part, bool userInterface, const DOMString &value)
{
return false;
}
bool execPaste(KHTMLPart *part, bool userInterface, const DOMString &value)
{
part->pasteFromPasteboard();
return true;
}
bool execPasteAndMatchStyle(KHTMLPart *part, bool userInterface, const DOMString &value)
{
part->pasteAndMatchStyle();
return true;
}
bool execPrint(KHTMLPart *part, bool userInterface, const DOMString &value)
{
part->print();
return true;
}
bool execRedo(KHTMLPart *part, bool userInterface, const DOMString &value)
{
part->redo();
return true;
}
bool execSelectAll(KHTMLPart *part, bool userInterface, const DOMString &value)
{
part->selectAll();
return true;
}
bool execSubscript(KHTMLPart *part, bool userInterface, const DOMString &value)
{
return execStyleChange(part, CSS_PROP_VERTICAL_ALIGN, "sub");
}
bool execSuperscript(KHTMLPart *part, bool userInterface, const DOMString &value)
{
return execStyleChange(part, CSS_PROP_VERTICAL_ALIGN, "super");
}
bool execTranspose(KHTMLPart *part, bool userInterface, const DOMString &value)
{
part->transpose();
return true;
}
bool execUnderline(KHTMLPart *part, bool userInterface, const DOMString &value)
{
bool isUnderlined = selectionStartHasStyle(part, CSS_PROP__KHTML_TEXT_DECORATIONS_IN_EFFECT, "underline");
return execStyleChange(part, CSS_PROP__KHTML_TEXT_DECORATIONS_IN_EFFECT, isUnderlined ? "none" : "underline");
}
bool execUndo(KHTMLPart *part, bool userInterface, const DOMString &value)
{
part->undo();
return true;
}
bool execUnselect(KHTMLPart *part, bool userInterface, const DOMString &value)
{
part->clearSelection();
return true;
}
bool enabled(KHTMLPart *part)
{
return true;
}
bool enabledAnySelection(KHTMLPart *part)
{
return part->selection().isCaretOrRange();
}
bool enabledPaste(KHTMLPart *part)
{
return supportsPasteCommand && part->canPaste();
}
bool enabledPasteAndMatchStyle(KHTMLPart *part)
{
return supportsPasteCommand && part->canPaste();
}
bool enabledRangeSelection(KHTMLPart *part)
{
return part->selection().isRange();
}
bool enabledRedo(KHTMLPart *part)
{
return part->canRedo();
}
bool enabledUndo(KHTMLPart *part)
{
return part->canUndo();
}
KHTMLPart::TriState stateNone(KHTMLPart *part)
{
return KHTMLPart::falseTriState;
}
KHTMLPart::TriState stateBold(KHTMLPart *part)
{
return stateStyle(part, CSS_PROP_FONT_WEIGHT, "bold");
}
KHTMLPart::TriState stateItalic(KHTMLPart *part)
{
return stateStyle(part, CSS_PROP_FONT_STYLE, "italic");
}
KHTMLPart::TriState stateSubscript(KHTMLPart *part)
{
return stateStyle(part, CSS_PROP_VERTICAL_ALIGN, "sub");
}
KHTMLPart::TriState stateSuperscript(KHTMLPart *part)
{
return stateStyle(part, CSS_PROP_VERTICAL_ALIGN, "super");
}
KHTMLPart::TriState stateUnderline(KHTMLPart *part)
{
return stateStyle(part, CSS_PROP_TEXT_DECORATION, "underline");
}
DOMString valueNull(KHTMLPart *part)
{
return DOMString();
}
DOMString valueBackColor(KHTMLPart *part)
{
return valueStyle(part, CSS_PROP_BACKGROUND_COLOR);
}
DOMString valueFontName(KHTMLPart *part)
{
return valueStyle(part, CSS_PROP_FONT_FAMILY);
}
DOMString valueFontSize(KHTMLPart *part)
{
return valueStyle(part, CSS_PROP_FONT_SIZE);
}
DOMString valueFontSizeDelta(KHTMLPart *part)
{
return valueStyle(part, CSS_PROP__KHTML_FONT_SIZE_DELTA);
}
DOMString valueForeColor(KHTMLPart *part)
{
return valueStyle(part, CSS_PROP_COLOR);
}
QDict<CommandImp> createCommandDictionary()
{
struct EditorCommand { const char *name; CommandImp imp; };
static const EditorCommand commands[] = {
{ "BackColor", { execBackColor, enabled, stateNone, valueBackColor } },
{ "Bold", { execBold, enabledAnySelection, stateBold, valueNull } },
{ "Copy", { execCopy, enabledRangeSelection, stateNone, valueNull } },
{ "Cut", { execCut, enabledRangeSelection, stateNone, valueNull } },
{ "Delete", { execDelete, enabledAnySelection, stateNone, valueNull } },
{ "FontName", { execFontName, enabledAnySelection, stateNone, valueFontName } },
{ "FontSize", { execFontSize, enabledAnySelection, stateNone, valueFontSize } },
{ "FontSizeDelta", { execFontSizeDelta, enabledAnySelection, stateNone, valueFontSizeDelta } },
{ "ForeColor", { execForeColor, enabledAnySelection, stateNone, valueForeColor } },
{ "ForwardDelete", { execForwardDelete, enabledAnySelection, stateNone, valueNull } },
{ "Indent", { execIndent, enabledAnySelection, stateNone, valueNull } },
{ "InsertLineBreak", { execInsertLineBreak, enabledAnySelection, stateNone, valueNull } },
{ "InsertParagraph", { execInsertParagraph, enabledAnySelection, stateNone, valueNull } },
{ "InsertText", { execInsertText, enabledAnySelection, stateNone, valueNull } },
{ "Italic", { execItalic, enabledAnySelection, stateItalic, valueNull } },
{ "JustifyCenter", { execJustifyCenter, enabledAnySelection, stateNone, valueNull } },
{ "JustifyFull", { execJustifyFull, enabledAnySelection, stateNone, valueNull } },
{ "JustifyLeft", { execJustifyLeft, enabledAnySelection, stateNone, valueNull } },
{ "JustifyNone", { execJustifyLeft, enabledAnySelection, stateNone, valueNull } },
{ "JustifyRight", { execJustifyRight, enabledAnySelection, stateNone, valueNull } },
{ "Outdent", { execOutdent, enabledAnySelection, stateNone, valueNull } },
{ "Paste", { execPaste, enabledPaste, stateNone, valueNull } },
{ "PasteAndMatchStyle", { execPasteAndMatchStyle, enabledPasteAndMatchStyle, stateNone, valueNull } },
{ "Print", { execPrint, enabled, stateNone, valueNull } },
{ "Redo", { execRedo, enabledRedo, stateNone, valueNull } },
{ "SelectAll", { execSelectAll, enabled, stateNone, valueNull } },
{ "Subscript", { execSubscript, enabledAnySelection, stateSubscript, valueNull } },
{ "Superscript", { execSuperscript, enabledAnySelection, stateSuperscript, valueNull } },
{ "Transpose", { execTranspose, enabled, stateNone, valueNull } },
{ "Underline", { execUnderline, enabledAnySelection, stateUnderline, valueNull } },
{ "Undo", { execUndo, enabledUndo, stateNone, valueNull } },
{ "Unselect", { execUnselect, enabledAnySelection, stateNone, valueNull } }
};
const int numCommands = sizeof(commands) / sizeof(commands[0]);
QDict<CommandImp> commandDictionary(numCommands, false); for (int i = 0; i < numCommands; ++i) {
commandDictionary.insert(commands[i].name, &commands[i].imp);
}
#ifndef NDEBUG
supportsPasteCommand = true;
#endif
return commandDictionary;
}
}
}