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.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed May 5 07:22:14 2004 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003