khtml Library API Documentation

khtml_caret_p.h

00001 /* This file is part of the KDE project 00002 * 00003 * Copyright (C) 2003 Leo Savernik <l.savernik@aon.at> 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Library General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Library General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Library General Public License 00016 * along with this library; see the file COPYING.LIB. If not, write to 00017 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 * Boston, MA 02111-1307, USA. 00019 */ 00020 00021 #ifndef KHTML_CARET_P_H 00022 #define KHTML_CARET_P_H 00023 00024 #include "rendering/render_table.h" 00025 00026 #define DEBUG_CARETMODE 0 00027 00028 namespace khtml { 00029 00033 struct CaretViewContext { 00034 int freqTimerId; // caret blink frequency timer id 00035 int x, y; // caret position in viewport coordinates 00036 // (y specifies the top, not the baseline) 00037 int width; // width of caret in pixels 00038 int height; // height of caret in pixels 00039 bool visible; // true if currently visible. 00040 bool displayed; // true if caret is to be displayed at all. 00041 bool caretMoved; // set to true once caret has been moved in page 00042 // how to display the caret when view is not focused 00043 KHTMLPart::CaretDisplayPolicy displayNonFocused; 00044 00052 int origX; 00053 00054 bool keyReleasePending; // true if keypress under caret mode awaits 00055 // corresponding release event 00056 CaretViewContext() : freqTimerId(-1), x(0), y(0), width(1), height(16), 00057 visible(true), displayed(false), caretMoved(false), 00058 displayNonFocused(KHTMLPart::CaretInvisible), origX(0), 00059 keyReleasePending(false) 00060 {} 00061 }; 00062 00066 struct EditorContext { 00067 bool override; // true if typed characters should override 00068 // the existing ones. 00069 00070 EditorContext() : override(false) 00071 {} 00072 }; 00073 00074 class LinearDocument; 00075 00085 class LineIterator 00086 { 00087 protected: 00088 LinearDocument *lines; // associated document 00089 RenderFlow *cb; // containing block 00090 InlineFlowBox *flowBox; // the line itself 00091 00092 static InlineBox *currentBox; // current inline box 00093 00094 // Note: cb == 0 indicates a position beyond the beginning or the 00095 // end of a document. 00096 00099 LineIterator() {} 00100 00107 LineIterator(LinearDocument *l, DOM::NodeImpl *node, long offset); 00108 00109 public: 00117 InlineFlowBox *operator *() const { return flowBox; } 00118 00123 LineIterator &operator ++(); 00131 LineIterator operator ++(int); 00132 00137 LineIterator &operator --(); 00145 LineIterator operator --(int); 00146 00152 LineIterator operator +(int summand) const; 00158 LineIterator operator -(int summand) const; 00159 00165 LineIterator &operator +=(int summand); 00171 LineIterator &operator -=(int summand); 00172 00176 bool operator ==(const LineIterator &it) const 00177 { 00178 return lines == it.lines 00179 && flowBox == it.flowBox && cb == it.cb; 00180 } 00181 00184 bool operator !=(const LineIterator &it) const 00185 { 00186 return !operator ==(it); 00187 } 00188 00198 static InlineBox *currentInlineBox() { return currentBox; } 00199 00200 protected: 00203 void nextBlock(); 00206 void prevBlock(); 00207 00208 friend class InlineBoxIterator; 00209 friend class EditableInlineBoxIterator; 00210 friend class LinearDocument; 00211 }; 00212 00213 00234 class LinearDocument { 00235 public: 00236 typedef LineIterator Iterator; 00237 00247 LinearDocument(KHTMLPart *part, DOM::NodeImpl *node, long offset); 00248 00249 virtual ~LinearDocument(); 00250 00259 bool isValid() const // FIXME: not yet impl'd 00260 { 00261 return true; 00262 } 00263 00271 int count() const; 00272 00277 Iterator current(); 00278 00282 const Iterator &end() const { return _end; } 00283 00287 Iterator preEnd(); 00288 00292 Iterator begin(); 00293 00298 const Iterator &preBegin() const { return _preBegin; } 00299 00300 protected: 00301 void initPreBeginIterator(); 00302 void initEndIterator(); 00303 00304 protected: 00305 RenderArena *arena; // We need an arena for intermediate render 00306 // objects that have no own inline box 00307 DOM::NodeImpl *node; 00308 long offset; 00309 00310 Iterator _preBegin; 00311 Iterator _end; 00312 00313 KHTMLPart *m_part; 00314 00315 friend class LineIterator; 00316 friend class EditableLineIterator; 00317 friend class ErgonomicEditableLineIterator; 00318 friend class InlineBoxIterator; 00319 friend class EditableInlineBoxIterator; 00320 friend class EditableCharacterIterator; 00321 }; 00322 00323 00334 class InlineBoxIterator { 00335 protected: 00336 RenderArena *arena; // arena for allocating transient inline boxes 00337 InlineBox *box; // currently traversed inline box 00338 00339 public: 00342 InlineBoxIterator(RenderArena *arena, InlineFlowBox *flowBox, bool fromEnd = false); 00343 00347 InlineBoxIterator(LineIterator &lit, bool fromEnd = false, 00348 InlineBox *initBox = 0); 00349 00352 InlineBoxIterator() {} 00353 00358 InlineBox *operator *() const { return box; } 00359 00362 InlineBoxIterator &operator ++(); 00363 00367 InlineBoxIterator &operator --(); 00368 }; 00369 00381 class EditableInlineBoxIterator : public InlineBoxIterator { 00382 protected: 00383 KHTMLPart *m_part; 00384 bool adjacent; 00385 00386 public: 00393 EditableInlineBoxIterator(KHTMLPart *part, RenderArena *arena, 00394 InlineFlowBox *flowBox, bool fromEnd = false) 00395 : InlineBoxIterator(arena, flowBox, fromEnd), m_part(part), adjacent(true) 00396 { 00397 if (box && !isEditable(box)) fromEnd ? --*this : ++*this; 00398 } 00399 00403 EditableInlineBoxIterator(LineIterator &lit, bool fromEnd = false, 00404 InlineBox *initBox = 0) 00405 : InlineBoxIterator(lit, fromEnd, initBox), m_part(lit.lines->m_part) 00406 { 00407 if (box && !isEditable(box)) 00408 { 00409 if (fromEnd) 00410 --*this; 00411 else 00412 ++*this; 00413 } 00414 } 00415 00418 EditableInlineBoxIterator() {} 00419 00423 bool isAdjacent() const { return adjacent; } 00424 00428 EditableInlineBoxIterator &operator ++() 00429 { 00430 adjacent = true; 00431 do { 00432 InlineBoxIterator::operator ++(); 00433 } while (box && !isEditable(box)); 00434 return *this; 00435 } 00436 00440 EditableInlineBoxIterator &operator --() 00441 { 00442 adjacent = true; 00443 do { 00444 InlineBoxIterator::operator --(); 00445 } while (box && !isEditable(box)); 00446 return *this; 00447 } 00448 00449 protected: 00454 bool isEditable(InlineBox *b) 00455 { 00456 //if (m_part->isCaretMode() || m_part->isEditable()) return true; 00457 00458 Q_ASSERT(b); 00459 RenderObject *r = b->object(); 00460 #if DEBUG_CARETMODE > 0 00461 if (b->isInlineFlowBox()) kdDebug(6200) << "b is inline flow box" << endl; 00462 kdDebug(6200) << "isEditable r" << r << ": " << (r ? r->renderName() : QString::null) << (r && r->isText() ? " contains \"" + QString(((RenderText *)r)->str->s, QMIN(((RenderText *)r)->str->l,15)) + "\"" : QString::null) << endl; 00463 #endif 00464 // Must check caret mode or design mode *after* r && r->element(), otherwise 00465 // lines without a backing DOM node get regarded, leading to a crash. 00466 // ### check should actually be in InlineBoxIterator 00467 bool result = r && r->element() && !r->isTableCol() 00468 && (m_part->isCaretMode() || m_part->isEditable() 00469 || r->style()->userInput() == UI_ENABLED); 00470 if (!result) adjacent = false; 00471 #if DEBUG_CARETMODE > 0 00472 kdDebug(6200) << result << endl; 00473 #endif 00474 return result; 00475 } 00476 00477 }; 00478 00495 class EditableLineIterator : public LineIterator { 00496 public: 00505 EditableLineIterator(const LineIterator &it, bool fromEnd = false) 00506 : LineIterator(it) 00507 { 00508 if (flowBox && !isEditable(*this)) 00509 { 00510 if (fromEnd) 00511 operator--(); 00512 else 00513 operator ++(); 00514 } 00515 if (!flowBox || !cb) { 00516 #if DEBUG_CARETMODE > 0 00517 kdDebug(6200) << "EditableLineIterator: findFlowBox failed" << endl; 00518 #endif 00519 cb = 0; 00520 }/*end if*/ 00521 } 00522 00527 EditableLineIterator() {} 00528 00533 EditableLineIterator &operator ++() 00534 { 00535 // FIXME: MEGA-FLAW! editable empty inlines elements not 00536 // represented by an inline box aren't considered any more. 00537 do { 00538 LineIterator::operator ++(); 00539 } while (cb && !isEditable(*this)); 00540 return *this; 00541 } 00549 //EditableLineIterator operator ++(int); 00550 00555 EditableLineIterator &operator --() 00556 { 00557 // FIXME: MEGA-FLAW! editable empty inlines not 00558 // represented by an inline box aren't considered any more. 00559 do { 00560 LineIterator::operator --(); 00561 } while (cb && !isEditable(*this)); 00562 return *this; 00563 } 00571 //EditableLineIterator operator --(int); 00572 00573 #if 0 // implement when it's needed 00574 00577 EditableLineIterator operator +(int summand) const; 00581 EditableLineIterator operator -(int summand) const; 00582 00586 EditableLineIterator &operator +=(int summand); 00590 EditableLineIterator &operator -=(int summand); 00591 #endif 00592 00593 protected: 00598 bool isEditable(LineIterator &it) 00599 { 00600 #if 0 // these shortcut evaluations are all invalid 00601 if (lines->m_part->isCaretMode() || lines->m_part->isEditable()) return true; 00602 00603 // on dummy lines check the containing block itself for editability 00604 if (!(*it)->firstChild()) { 00605 kdDebug(6200) << "cb " << cb->renderName() << "[" << cb << "](" << (cb->element() ? cb->element()->nodeName().string() : QString::null) << ") editable? " << (cb->style()->userInput() == UI_ENABLED) << endl; 00606 return cb->style()->userInput() == UI_ENABLED; 00607 }/*end if*/ 00608 #endif 00609 00610 EditableInlineBoxIterator fbit = it; 00611 return *fbit; 00612 } 00613 00614 }; 00615 00624 class TableRowIterator { 00625 protected: 00626 TableSectionIterator sec; // current section 00627 int index; // index of row within section 00628 public: 00635 TableRowIterator(RenderTable *table, bool fromEnd = false, 00636 RenderTableSection::RowStruct *row = 0); 00637 00642 TableRowIterator(RenderTableSection *section, int index) 00643 : sec(section), index(index) 00644 {} 00645 00649 TableRowIterator() {} 00650 00654 RenderTableSection::RowStruct *operator *() 00655 { 00656 if (!*sec) return 0; 00657 return &(*sec)->grid[index]; 00658 } 00659 00662 TableRowIterator &operator ++(); 00663 00666 TableRowIterator &operator --(); 00667 00668 protected: 00669 }; 00670 00686 class ErgonomicEditableLineIterator : public EditableLineIterator { 00687 protected: 00688 int xCoor; // x-coordinate to determine cell position with 00689 public: 00694 ErgonomicEditableLineIterator(const LineIterator &it, int x) 00695 : EditableLineIterator(it), xCoor(x) {} 00696 00700 ErgonomicEditableLineIterator() {} 00701 00706 ErgonomicEditableLineIterator &operator ++(); 00707 00712 ErgonomicEditableLineIterator &operator --(); 00713 00714 protected: 00722 void determineTopologicalElement(RenderTableCell *oldCell, 00723 RenderObject *newObject, bool toBegin); 00724 00730 void calcAndStoreNewLine(RenderFlow *newBlock, bool toBegin); 00731 00732 #if 0 00733 00737 static bool belongToSameTable(const RenderTableCell *t1, const RenderTableCell *t2) 00738 { 00739 return t1 && t2 && t1->table() == t2->table(); 00740 } 00741 00755 static RenderTableCell *findNearestTableCellInSection(KHTMLPart *part, int x, 00756 RenderTableSection *section, bool fromEnd = false, int startIndex = -1); 00757 00768 RenderObject *findObjectBeyond(RenderTable *table, bool toBegin); 00769 #endif 00770 }; 00771 00779 class EditableCharacterIterator { 00780 protected: 00781 LinearDocument *ld; 00782 EditableLineIterator _it; 00783 EditableInlineBoxIterator ebit; 00784 DOM::NodeImpl *_node; 00785 long _offset; 00786 int _char; 00787 00788 public: 00789 00795 EditableCharacterIterator() {} 00796 00801 EditableCharacterIterator(LinearDocument *ld) 00802 : ld(ld), _it(ld->current()), 00803 ebit(_it, false, _it.currentInlineBox()), _char(-1) 00804 { 00805 _node = ld->node; 00806 _offset = ld->offset; 00807 00808 // ### temporary fix for illegal nodes 00809 if (_it == ld->end()) { _node = 0; return; } 00810 00811 // seeks the node's inline box 00812 // ### redundant, implement means to get it from ld or _it 00813 // ### if node is not there? 00814 EditableInlineBoxIterator copy = ebit; 00815 for (; *ebit; ++ebit) { 00816 copy = ebit; 00817 InlineBox *b = *ebit; 00818 00819 if (b == _it.currentInlineBox() || b->object() == _node->renderer()) { 00820 _offset = QMIN(kMax(_offset, b->minOffset()), b->maxOffset()); 00821 break; 00822 }/*end if*/ 00823 }/*next ebit*/ 00824 // If no node is found, we take the last editable node. This is a very 00825 // feeble approximation as it sometimes makes the caret get stuck, or 00826 // iterate over the same element indefinitely, 00827 // but this covers up a case that should never happen in theory. 00828 if (!*ebit) { 00829 // this is a really bad hack but solves the caret-gets-stuck issue 00830 static long cache_offset = -1; 00831 ebit = copy; 00832 InlineBox *b = *ebit; 00833 _node = b->object()->element(); 00834 long max_ofs = b->maxOffset(); 00835 _offset = cache_offset == max_ofs ? b->minOffset() : max_ofs; 00836 cache_offset = _offset; 00837 #if DEBUG_CARETMODE > 0 00838 kdDebug(6200) << "There was no node! Fixup applied!" << endl; 00839 if (cache_offset == max_ofs) kdDebug(6200) << "offset fixup applied as well" << endl; 00840 #endif 00841 }/*end if*/ 00842 00843 initFirstChar(); 00844 } 00845 00849 int chr() const { return _char; } 00850 00854 QChar operator *() const { return QChar(_char >= 0 ? _char : ' '); } 00855 00858 long offset() const { return _offset; } 00863 DOM::NodeImpl *node() const { return _node; } 00870 InlineBox *box() const { return *ebit; } 00873 EditableCharacterIterator &operator ++(); 00874 00877 EditableCharacterIterator &operator --(); 00878 00879 protected: 00883 void initFirstChar(); 00886 void peekNext() 00887 { 00888 EditableInlineBoxIterator copy = ebit; 00889 ++copy; 00890 InlineBox *b = *copy; 00891 if (b && b->isInlineTextBox()) 00892 _char = static_cast<RenderText *>(b->object())->str->s[b->minOffset()].unicode(); 00893 else 00894 _char = -1; 00895 } 00898 void peekPrev() 00899 { 00900 --ebit; 00901 // _peekPrev = *ebit; 00902 } 00903 00904 }; 00905 00906 00907 } 00908 00909 00910 #endif
KDE Logo
This file is part of the documentation for khtml Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Oct 8 11:16:07 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003