26 #include "css/css_renderstyledeclarationimpl.h" 27 #include "css/css_valueimpl.h" 28 #include "xml/dom_selection.h" 29 #include "xml/dom_docimpl.h" 30 #include "xml/dom_elementimpl.h" 31 #include "xml/dom_textimpl.h" 32 #include "xml/dom2_rangeimpl.h" 43 # define assert(x) Q_ASSERT(x) 46 #define PREPARE_JSEDITOR_CALL(command, retval) \ 47 JSEditor *js = m_part->xmlDocImpl() ? m_part->xmlDocImpl()->jsEditor() : 0; \ 48 if (!js) return retval; \ 49 const CommandImp *imp = js->commandImp(command) 51 #define DEBUG_COMMANDS 57 using khtml::RenderStyleDeclarationImpl;
84 RefPtr<EditCommandImpl> m_lastEditCommand;
94 :
d(
new EditorPrivate), m_typingStyle(0), m_part(part) {
99 m_typingStyle->deref();
106 return js->execCommand(imp, userInterface, value);
109 bool Editor::queryCommandEnabled(
const DOMString &command)
112 return js->queryCommandEnabled(imp);
115 bool Editor::queryCommandIndeterm(
const DOMString &command)
118 return js->queryCommandIndeterm(imp);
121 bool Editor::queryCommandState(
const DOMString &command)
124 return js->queryCommandState(imp);
127 bool Editor::queryCommandSupported(
const DOMString &command)
130 return js->queryCommandSupported(imp);
136 return js->queryCommandValue(imp);
142 return js->execCommand(imp, userInterface, value);
148 return js->queryCommandEnabled(imp);
154 return js->queryCommandIndeterm(imp);
160 return js->queryCommandState(imp);
166 return js->queryCommandSupported(imp);
172 return js->queryCommandValue(imp);
198 bool Editor::canPaste()
const 206 if (
d->m_redo.isEmpty())
208 RefPtr<EditCommandImpl> e =
d->m_redo.pop();
214 if (
d->m_undo.isEmpty())
216 RefPtr<EditCommandImpl> e =
d->m_undo.pop();
220 bool Editor::canRedo()
const 222 return !
d->m_redo.isEmpty();
225 bool Editor::canUndo()
const 227 return !
d->m_undo.isEmpty();
230 void Editor::applyStyle(CSSStyleDeclarationImpl *style)
232 switch (m_part->caret().state()) {
233 case Selection::NONE:
236 case Selection::CARET:
238 setTypingStyle(style);
240 case Selection::RANGE:
241 if (m_part->xmlDocImpl() && style) {
242 #ifdef DEBUG_COMMANDS 243 kDebug() <<
"[create ApplyStyleCommand]" << endl;
254 QListIterator<CSSProperty*> it(*desiredStyle->values());
255 while (it.hasNext()) {
256 int propertyID = it.next()->id();
257 DOMString desiredProperty = desiredStyle->getPropertyValue(propertyID);
258 DOMString computedProperty = computedStyle->getPropertyValue(propertyID);
260 ? Editor::TrueTriState : Editor::FalseTriState;
262 state = propertyState;
264 }
else if (state != propertyState) {
265 state = Editor::MixedTriState;
277 if (ctx->
m_selection.state() != Selection::RANGE) {
278 NodeImpl *nodeToRemove;
279 CSSStyleDeclarationImpl *selectionStyle = selectionComputedStyle(nodeToRemove);
281 return FalseTriState;
282 selectionStyle->ref();
283 updateState(style, selectionStyle, atStart, state);
284 selectionStyle->deref();
286 int exceptionCode = 0;
287 nodeToRemove->remove(exceptionCode);
288 assert(exceptionCode == 0);
291 for (NodeImpl *node = ctx->
m_selection.start().node(); node; node = node->traverseNextNode()) {
292 if (node->isHTMLElement()) {
293 CSSStyleDeclarationImpl *computedStyle =
new RenderStyleDeclarationImpl(node);
294 computedStyle->ref();
296 computedStyle->deref();
297 if (state == MixedTriState)
310 NodeImpl *nodeToRemove;
311 CSSStyleDeclarationImpl *selectionStyle = selectionComputedStyle(nodeToRemove);
315 selectionStyle->ref();
319 QListIterator<CSSProperty*> it(*style->values());
320 while (it.hasNext()) {
321 int propertyID = it.next()->id();
322 DOMString desiredProperty = style->getPropertyValue(propertyID);
323 DOMString selectionProperty = selectionStyle->getPropertyValue(propertyID);
324 if (
strcasecmp(selectionProperty, desiredProperty) != 0) {
330 selectionStyle->deref();
333 int exceptionCode = 0;
334 nodeToRemove->
remove(exceptionCode);
335 assert(exceptionCode == 0);
341 DOMString Editor::selectionStartStylePropertyValue(
int stylePropertyID)
const 343 NodeImpl *nodeToRemove;
344 CSSStyleDeclarationImpl *selectionStyle = selectionComputedStyle(nodeToRemove);
348 selectionStyle->ref();
349 DOMString value = selectionStyle->getPropertyValue(stylePropertyID);
350 selectionStyle->deref();
353 int exceptionCode = 0;
354 nodeToRemove->
remove(exceptionCode);
355 assert(exceptionCode == 0);
361 CSSStyleDeclarationImpl *Editor::selectionComputedStyle(NodeImpl *&nodeToRemove)
const 365 if (!m_part->xmlDocImpl())
373 Position pos(range.startContainer().handle(), range.startOffset());
375 ElementImpl *elem = pos.element();
376 ElementImpl *styleElement = elem;
377 int exceptionCode = 0;
380 styleElement = m_part->xmlDocImpl()->createHTMLElement(
"SPAN");
383 styleElement->setAttribute(ATTR_STYLE, m_typingStyle->cssText().implementation());
386 TextImpl *text = m_part->xmlDocImpl()->createEditingTextNode(
"");
387 styleElement->appendChild(text, exceptionCode);
388 assert(exceptionCode == 0);
390 elem->appendChild(styleElement, exceptionCode);
391 assert(exceptionCode == 0);
393 nodeToRemove = styleElement;
396 return new RenderStyleDeclarationImpl(styleElement);
399 PassRefPtr<EditCommandImpl> Editor::lastEditCommand()
const 401 return d->m_lastEditCommand;
406 #ifdef DEBUG_COMMANDS 407 kDebug() <<
"[Applied editing]" << endl;
411 m_part->xmlDocImpl()->updateLayout();
415 if (
d->m_lastEditCommand == cmd) {
420 d->registerUndo(cmd);
421 d->m_lastEditCommand = cmd;
423 m_part->editorContext()->m_selection.setNeedsLayout(
true);
424 m_part->selectionLayoutChanged();
432 m_part->xmlDocImpl()->updateLayout();
435 d->registerRedo(cmd);
437 KWQ(
this)->respondToChangedContents();
439 m_part->editorContext()->m_selection.setNeedsLayout(
true);
440 m_part->selectionLayoutChanged();
444 d->m_lastEditCommand = 0;
450 m_part->xmlDocImpl()->updateLayout();
453 d->registerUndo(cmd,
false );
455 KWQ(
this)->respondToChangedContents();
457 m_part->selectionLayoutChanged();
461 d->m_lastEditCommand = 0;
464 CSSStyleDeclarationImpl *Editor::typingStyle()
const 466 return m_typingStyle;
469 void Editor::setTypingStyle(CSSStyleDeclarationImpl *style)
471 CSSStyleDeclarationImpl *old = m_typingStyle;
472 m_typingStyle = style;
474 m_typingStyle->ref();
479 void Editor::clearTypingStyle()
484 void Editor::closeTyping()
488 static_cast<TypingCommandImpl*>(lastCommand)->closeTyping();
491 void Editor::indent()
494 IndentOutdentCommandImpl::Indent);
498 void Editor::outdent()
501 IndentOutdentCommandImpl::Outdent);
505 bool Editor::handleKeyEvent(QKeyEvent *_ke)
507 bool handled =
false;
509 bool ctrl = _ke->modifiers() & Qt::ControlModifier;
510 bool alt = _ke->modifiers() & Qt::AltModifier;
512 bool meta = _ke->modifiers() & Qt::MetaModifier;
514 if (ctrl || alt || meta) {
520 case Qt::Key_Delete: {
521 Selection selectionToDelete = m_part->caret();
522 #ifdef DEBUG_COMMANDS 523 kDebug(6200) <<
"========== KEY_DELETE ==========" << endl;
525 if (selectionToDelete.state() == Selection::CARET) {
526 Position pos(selectionToDelete.start());
527 #ifdef DEBUG_COMMANDS 528 kDebug(6200) <<
"pos.inLastEditableInRootEditableElement " << pos.inLastEditableInRootEditableElement() <<
" pos.offset " << pos.offset() <<
" pos.max " << pos.node()->caretMaxRenderedOffset() << endl;
530 if (pos.nextCharacterPosition() == pos) {
532 #ifdef DEBUG_COMMANDS 533 kDebug(6200) <<
"no delete!!!!!!!!!!" << endl;
537 m_part->d->editor_context.m_selection
538 = Selection(pos, pos.nextCharacterPosition());
542 case Qt::Key_Backspace:
543 TypingCommandImpl::deleteKeyPressed0(m_part->xmlDocImpl());
550 TypingCommandImpl::insertNewline0(m_part->xmlDocImpl());
564 if (m_part->caret().state() != Selection::CARET) {
568 kDebug(6200) <<
"Editable node w/o caret!";
569 DOM::NodeImpl* focus = m_part->xmlDocImpl()->focusNode();
570 if (m_part->caret().state() == Selection::NONE) {
572 m_part->setCaret(Position(focus, focus->caretMinOffset()));
578 if (!_ke->text().isEmpty()) {
579 TypingCommandImpl::insertText0(m_part->xmlDocImpl(), _ke->text());
595 #include "editor.moc" Contextual information about the caret and the built-in editor.
KAction * print(const QObject *recvr, const char *slot, QObject *parent)
KAction * cut(const QObject *recvr, const char *slot, QObject *parent)
EditorCommand
List of all supported built-in editor commands.
DOM::Selection m_selection
KAction * copy(const QObject *recvr, const char *slot, QObject *parent)
bool strcasecmp(const DOMString &a, const DOMString &b)
void remove(unsigned int pos, int len=1)
This class is khtml's main class.
#define PREPARE_JSEDITOR_CALL(command, retval)
DOM::Selection startingSelection() const
DOM::Selection endingSelection() const
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
static const int sMaxUndoSteps
TriState
Tri-state boolean.
This class implements the basic string we use in the DOM.
virtual bool isTypingCommand() const
static bool selectionStartHasStyle(KHTMLPart *part, int propertyID, const char *desiredValue)
This library provides a full-featured HTML parser and widget.
static void updateState(CSSStyleDeclarationImpl *desiredStyle, CSSStyleDeclarationImpl *computedStyle, bool &atStart, Editor::TriState &state)
This is the BrowserExtension for a KHTMLPart document.