]> git.saurik.com Git - wxWidgets.git/commitdiff
1. crash when deleting multi line selection fixed
authorVadim Zeitlin <vadim@wxwidgets.org>
Sat, 12 Jun 1999 21:07:44 +0000 (21:07 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sat, 12 Jun 1999 21:07:44 +0000 (21:07 +0000)
2. BreakLine() does just discard the first line (wreaking total havoc) any
   more
3. ScrollToCursor() actually scrolls to cursor
4. style change affects the first line too - and since the first time, style
   doesn't change mysteriously any more after second Clear()
5. word cursor movement even better (did I get it right this time?)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@2766 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

samples/richedit/wxLayout.cpp
samples/richedit/wxllist.cpp
samples/richedit/wxllist.h
samples/richedit/wxlparser.cpp
samples/richedit/wxlwindow.cpp
samples/richedit/wxlwindow.h

index 265ead4ebc5810d1deb4aab8b6ab4013a1e9c757..d00d2a2186eaaf472a355d2ea58429b7271e96c5 100644 (file)
@@ -33,19 +33,22 @@ IMPLEMENT_APP(MyApp)
 // MyFrame
 //-----------------------------------------------------------------------------
 
-   enum ids{ ID_ADD_SAMPLE = 1, ID_CLEAR, ID_PRINT,
-             ID_PRINT_SETUP, ID_PAGE_SETUP, ID_PREVIEW, ID_PRINT_PS,
-             ID_PRINT_SETUP_PS, ID_PAGE_SETUP_PS,ID_PREVIEW_PS,
-             ID_WRAP, ID_NOWRAP, ID_PASTE, ID_COPY, ID_CUT,
-             ID_PASTE_PRIMARY,
-             ID_FIND,
-             ID_WXLAYOUT_DEBUG, ID_QUIT, ID_CLICK, ID_HTML, ID_TEXT,
-             ID_TEST, ID_LINEBREAKS_TEST, ID_LONG_TEST, ID_URL_TEST };
+enum ids
+{
+    ID_ADD_SAMPLE = 1, ID_CLEAR, ID_PRINT,
+    ID_PRINT_SETUP, ID_PAGE_SETUP, ID_PREVIEW, ID_PRINT_PS,
+    ID_PRINT_SETUP_PS, ID_PAGE_SETUP_PS,ID_PREVIEW_PS,
+    ID_WRAP, ID_NOWRAP, ID_PASTE, ID_COPY, ID_CUT,
+    ID_PASTE_PRIMARY,
+    ID_FIND,
+    ID_WXLAYOUT_DEBUG, ID_QUIT, ID_CLICK, ID_HTML, ID_TEXT,
+    ID_TEST, ID_LINEBREAKS_TEST, ID_LONG_TEST, ID_URL_TEST
+};
 
 
 IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame )
 
-   BEGIN_EVENT_TABLE(MyFrame,wxFrame)
+BEGIN_EVENT_TABLE(MyFrame,wxFrame)
    EVT_MENU(ID_PRINT, MyFrame::OnPrint)
    EVT_MENU(ID_PREVIEW, MyFrame::OnPrintPreview)
    EVT_MENU(ID_PRINT_SETUP, MyFrame::OnPrintSetup)
@@ -57,7 +60,7 @@ IMPLEMENT_DYNAMIC_CLASS( MyFrame, wxFrame )
    EVT_MENU    (-1,       MyFrame::OnCommand)
    EVT_COMMAND (-1,-1,    MyFrame::OnCommand)
    EVT_CHAR    (  wxLayoutWindow::OnChar  )
-   END_EVENT_TABLE()
+END_EVENT_TABLE()
 
 
 MyFrame::MyFrame(void) :
@@ -119,8 +122,8 @@ MyFrame::MyFrame(void) :
    m_lwin->SetMouseTracking(true);
    m_lwin->SetEditable(true);
    m_lwin->SetWrapMargin(40);
-   m_lwin->Clear(wxROMAN,16,wxNORMAL,wxNORMAL, false);
    m_lwin->SetFocus();
+   Clear();
 
    // create and set the background bitmap (this will result in a lattice)
    static const int sizeBmp = 10;
index ca7b2b7587e42e84f579dfe351c4e9d657be68fd..e2c36139772bf9f3fcccd74f382d0b870c1c35d3 100644 (file)
@@ -622,20 +622,25 @@ wxLayoutObjectCmd::Layout(wxDC &dc, class wxLayoutList * llist)
 
 wxLayoutLine::wxLayoutLine(wxLayoutLine *prev, wxLayoutList *llist)
 {
-   m_LineNumber = 0;
    m_Width = m_Height = 0;
    m_Length = 0;
+
    m_updateLeft = -1;
    MarkDirty(0);
+
    m_Previous = prev;
    m_Next = NULL;
+
+   m_LineNumber = 0;
    RecalculatePosition(llist);
+
    if(m_Previous)
    {
-      m_LineNumber = m_Previous->GetLineNumber()+1;
+      m_LineNumber = m_Previous->GetLineNumber() + 1;
       m_Next = m_Previous->GetNextLine();
       m_Previous->m_Next = this;
    }
+
    if(m_Next)
    {
       m_Next->m_Previous = this;
@@ -736,30 +741,45 @@ wxLayoutLine::FindObject(CoordType xpos, CoordType *offset) const
 }
 
 wxLayoutObjectList::iterator
-wxLayoutLine::FindObjectScreen(wxDC &dc,
+wxLayoutLine::FindObjectScreen(wxDC &dc, wxLayoutList *llist,
                                CoordType xpos, CoordType *cxpos,
                                bool *found) const
 {
    wxASSERT(cxpos);
-   wxASSERT(cxpos);
+
+   llist->ApplyStyle(GetStyleInfo(), dc);
+
    wxLayoutObjectList::iterator i;
    CoordType x = 0, cx = 0, width;
 
    for(i = m_ObjectList.begin(); i != NULLIT; i++)
    {
-      width = (**i).GetWidth();
+      wxLayoutObject *obj = *i;
+      if ( obj->GetType() == WXLO_TYPE_CMD )
+      {
+         // this will set the correct font for the objects which follow
+         obj->Layout(dc, llist);
+      }
+
+      width = obj->GetWidth();
       if( x <= xpos && xpos <= x + width )
       {
-         *cxpos = cx + (**i).GetOffsetScreen(dc, xpos-x);
-         if(found) *found = true;
+         *cxpos = cx + obj->GetOffsetScreen(dc, xpos-x);
+
+         if ( found )
+             *found = true;
          return i;
       }
-      x += (**i).GetWidth();
-      cx += (**i).GetLength();
+
+      x += obj->GetWidth();
+      cx += obj->GetLength();
    }
+
    // behind last object:
    *cxpos = cx;
-   if(found) *found = false;
+
+   if (found)
+       *found = false;
    return m_ObjectList.tail();
 }
 
@@ -1012,10 +1032,18 @@ wxLayoutLine::DeleteLine(bool update, wxLayoutList *llist)
    if(m_Previous)
        m_Previous->m_Next = m_Next;
 
+   wxLayoutLine *next = m_Next;
+   if ( next )
+   {
+      // get the line numbers right again
+      next->MoveLines(-1);
+   }
+
    if(update)
    {
-      m_Next->MoveLines(-1);
-      m_Next->RecalculatePositions(1, llist);
+      if ( next )
+         next->RecalculatePositions(1, llist);
+
       /* We assume that if we have more than one object in the list,
          this means that we have a command object, so we need to
          update the following lines. */
@@ -1025,7 +1053,7 @@ wxLayoutLine::DeleteLine(bool update, wxLayoutList *llist)
          )
          MarkNextDirty(-1);
    }
-   wxLayoutLine *next = m_Next;
+
    delete this;
 
    llist->DecNumLines();
@@ -1367,6 +1395,8 @@ wxLayoutLine::MergeNextLine(wxLayoutList *llist)
 #endif // 0
    }
 
+   llist->DecNumLines();
+
    delete oldnext;
 }
 
@@ -1531,6 +1561,7 @@ wxLayoutList::wxLayoutList()
 wxLayoutList::~wxLayoutList()
 {
    InternalClear();
+   Empty();
    m_FirstLine->DeleteLine(false, this);
 
    wxASSERT_MSG( m_numLines == 0, "line count calculation broken" );
@@ -1555,7 +1586,6 @@ wxLayoutList::Empty(void)
 void
 wxLayoutList::InternalClear(void)
 {
-   Empty();
    m_Selection.m_selecting = false;
    m_Selection.m_valid = false;
 
@@ -1620,6 +1650,11 @@ wxLayoutList::Clear(int family, int size, int style, int weight,
    m_DefaultStyleInfo = wxLayoutStyleInfo(family, size, style, weight,
                                         underline, fg, bg);
    m_CurrentStyleInfo = m_DefaultStyleInfo;
+
+   // Empty() should be called after we set m_DefaultStyleInfo because
+   // otherwise the style info for the first line (created in Empty()) would be
+   // incorrect
+   Empty();
 }
 
 wxPoint
@@ -1787,14 +1822,51 @@ wxLayoutList::MoveCursorWord(int n, bool untilNext)
 
    CoordType moveDistance = 0;
    CoordType offset;
-   for ( wxLOiterator i = m_CursorLine->FindObject(m_CursorPos.x, &offset);
+   wxLayoutLine *lineCur = m_CursorLine;
+   for ( wxLOiterator i = lineCur->FindObject(m_CursorPos.x, &offset);
          n != 0;
          n > 0 ? i++ : i-- )
    {
       if ( i == NULLIT )
-         return false;
+      {
+         if ( n > 0 )
+         {
+            // moving forward, pass to the first object of the next line
+            moveDistance++;
+            lineCur = lineCur->GetNextLine();
+            if ( lineCur )
+               i = lineCur->GetFirstObject();
+         }
+         else
+         {
+            // moving backwards, pass to the last object of the prev line
+            moveDistance--;
+            lineCur = lineCur->GetPreviousLine();
+            if ( lineCur )
+               i = lineCur->GetLastObject();
+         }
+
+         if ( i == NULLIT )
+         {
+            // moved to the end/beginning of text
+            return false;
+         }
+      }
 
       wxLayoutObject *obj = *i;
+
+      if ( offset == -1 )
+      {
+         // calculate offset: we are either at the very beginning or the very
+         // end of the object, so it isn't very difficult (the only time when
+         // offset is != -1 is for the very first iteration when its value is
+         // returned by FindObject)
+         if ( n > 0 )
+            offset = 0;
+         else
+            offset = obj->GetLength();
+      }
+
       if( obj->GetType() != WXLO_TYPE_TEXT )
       {
          // any visible non text objects count as one word
@@ -1817,9 +1889,11 @@ wxLayoutList::MoveCursorWord(int n, bool untilNext)
             if ( n > 0 )
             {
                // can't move further in this text object
-               n--;
-
                canAdvance = false;
+
+               // still should move over the object border
+               moveDistance++;
+               n--;
             }
             else if ( offset > 0 )
             {
@@ -1871,14 +1945,26 @@ wxLayoutList::MoveCursorWord(int n, bool untilNext)
                }
             }
 
-            n > 0 ? n-- : n++;
+            CoordType moveDelta = p - start - offset;
+            if ( (n < 0) && (offset == tobj->GetLength() - 1) )
+            {
+               // because we substracted 1 from offset in this case above, now
+               // compensate for it
+               moveDelta--;
+            }
+
+            if ( moveDelta != 0 )
+            {
+               moveDistance += moveDelta;
 
-            moveDistance = p - start - offset;
+               n > 0 ? n-- : n++;
+            }
          }
       }
 
-      // except for the first iteration, offset is 0
-      offset = 0;
+      // except for the first iteration, offset is calculated in the beginning
+      // of the loop
+      offset = -1;
    }
 
    MoveCursorHorizontally(moveDistance);
@@ -1952,7 +2038,6 @@ bool
 wxLayoutList::LineBreak(void)
 {
    wxASSERT(m_CursorLine);
-   bool setFirst = (m_CursorLine == m_FirstLine && m_CursorPos.x == 0);
 
    AddCursorPosToUpdateRect();
 
@@ -1963,14 +2048,9 @@ wxLayoutList::LineBreak(void)
       height = m_CursorLine->GetHeight();
 
    m_CursorLine = m_CursorLine->Break(m_CursorPos.x, this);
-   if(setFirst) // we were at beginning of first line
-      m_FirstLine = m_CursorLine;
-   wxASSERT(m_FirstLine);
-   if(m_CursorPos.x != 0)
-      m_CursorPos.y++;
+   m_CursorPos.y++;
    m_CursorPos.x = 0;
 
-
    // The following code will produce a height which is guaranteed to
    // be too high: old lineheight + the height of both new lines.
    // We can probably drop the old line height and start with height = 
@@ -2321,8 +2401,8 @@ wxLayoutList::FindObjectScreen(wxDC &dc, wxPoint const pos,
        cursorPos->y = line->GetLineNumber();
 
    // Now, find the object in the line:
-   ApplyStyle(line->GetStyleInfo(), dc);
-   wxLOiterator i = line->FindObjectScreen(dc, pos.x,
+   wxLOiterator i = line->FindObjectScreen(dc, this,
+                                           pos.x,
                                            cursorPos ? &cursorPos->x : NULL,
                                            found);
    return (i == NULLIT) ? NULL : *i;
@@ -2575,44 +2655,29 @@ wxLayoutList::DeleteSelection(void)
       return;
    }
 
+   // We now know that the two lines are different:
 
    wxLayoutLine
-      * firstLine = NULL,
-      * lastLine = NULL;
-
-   for(firstLine = m_FirstLine;
-       firstLine && firstLine->GetLineNumber() < m_Selection.m_CursorA.y;
-       firstLine=firstLine->GetNextLine())
-      ;
-   if(!firstLine || firstLine->GetLineNumber() != m_Selection.m_CursorA.y)
-      return;
-
-
-   for(lastLine = m_FirstLine;
-       lastLine && lastLine->GetLineNumber() < m_Selection.m_CursorB.y;
-       lastLine=lastLine->GetNextLine())
-      ;
-   if(!lastLine || lastLine->GetLineNumber() != m_Selection.m_CursorB.y)
-      return;
-
-
-   // We now know that the two lines are different:
+      * firstLine = GetLine(m_Selection.m_CursorA.y),
+      * lastLine = GetLine(m_Selection.m_CursorB.y);
 
    // First, delete what's left of this line:
    MoveCursorTo(m_Selection.m_CursorA);
    DeleteToEndOfLine();
 
-   wxLayoutLine *nextLine = firstLine->GetNextLine();
+   wxLayoutLine *prevLine = firstLine->GetPreviousLine(),
+                *nextLine = firstLine->GetNextLine();
    while(nextLine && nextLine != lastLine)
       nextLine = nextLine->DeleteLine(false, this);
 
    // Now nextLine = lastLine;
    Delete(1); // This joins firstLine and nextLine
-   Delete(m_Selection.m_CursorB.x); // This deletes the first x
-   // positions
+   Delete(m_Selection.m_CursorB.x); // This deletes the first x positions
 
-   /// Recalculate:
-   firstLine->RecalculatePositions(1, this);
+   // Recalculate the line positions and numbers but notice that firstLine
+   // might not exist any more - it could be deleted by Delete(1) above
+   wxLayoutLine *firstLine2 = prevLine ? prevLine->GetNextLine() : m_FirstLine;
+   firstLine2->RecalculatePositions(1, this);
 }
 
 /// Starts highlighting the selection
index 9c70ecbf407274cc0d533dd36c0a6b7771bbf634..5874e64dac6b9c679b161d0fb6125617b1b99af7 100644 (file)
@@ -520,12 +520,14 @@ public:
    /** Finds the object which covers the screen position xpos in this
        line.
        @param dc the wxDC to use for calculations
+       @param llist the layout list to which this line belongs
        @param xpos the screen x coordinate
        @param offset where to store the difference between xpos and
        the object's head
        @return iterator to the object or NULLIT
    */
    wxLayoutObjectList::iterator FindObjectScreen(wxDC &dc,
+                                                 wxLayoutList *llist,
                                                  CoordType xpos,
                                                  CoordType *offset,
                                                  bool *found = NULL) const ;
@@ -541,11 +543,18 @@ public:
        functions to export the list.
        @return iterator to the first object
    */
-   wxLayoutObjectList::iterator GetFirstObject(void)
+   wxLayoutObjectList::iterator GetFirstObject(void) const
       {
          return m_ObjectList.begin();
       }
 
+   /** Get the last object in the list.
+    */
+   wxLayoutObjectList::iterator GetLastObject(void) const
+      {
+         return m_ObjectList.tail();
+      }
+
    /** Deletes this line, returns pointer to next line.
        @param update If true, update all following lines.
    */
@@ -600,13 +609,14 @@ public:
        for that position
        @return pointer to the object
    */
-   wxLayoutObject * FindObjectScreen(wxDC &dc, CoordType xpos, bool
-                                     *found = NULL);
+   wxLayoutObject * FindObjectScreen(wxDC &dc,
+                                     CoordType xpos,
+                                     bool *found = NULL);
    /** This sets the style info for the beginning of this line.
        @param si styleinfo structure
     */
    void ApplyStyle(const wxLayoutStyleInfo &si)
-      {   m_StyleInfo = si; }
+      { m_StyleInfo = si; }
 
    //@}
 
@@ -1123,6 +1133,26 @@ public:
    void IncNumLines() { m_numLines++; }
    void DecNumLines() { m_numLines--; }
 
+   /// get the line by number
+   wxLayoutLine *GetLine(CoordType index) const
+   {
+       wxASSERT_MSG( (0 <= index) && (index < (CoordType)m_numLines),
+                     "invalid index" );
+
+       wxLayoutLine *line;
+       CoordType n = index;
+       for ( line = m_FirstLine; line && n-- > 0; line = line->GetNextLine() )
+           ;
+
+       if ( line )
+       {
+          // should be the right one
+          wxASSERT( line->GetLineNumber() == index );
+       }
+
+       return line;
+   }
+
 private:
    /// Clear the list.
    void InternalClear(void);
index 316247bfc0004c27c084da7663347e8d98ebd246..b3a961e3746f4565ecd70d5d880d4f623e94d41e 100644 (file)
@@ -41,10 +41,9 @@ void wxLayoutImportText(wxLayoutList *list, wxString const &str)
    if ( !str )
       return;
 
-   // we change the string temporarily inside this function
-   wxString& s = (wxString &)str; // const_cast
-
-   char * cptr = s.GetWriteBuf(s.Len());
+   // we change the string only temporarily inside this function
+   // VZ: I still don't like it... the string data may be shared...
+   char * cptr = (char *)str.c_str(); // const_cast
    const char * begin = cptr;
    char  backup;
 
@@ -70,8 +69,6 @@ void wxLayoutImportText(wxLayoutList *list, wxString const &str)
          break;
       cptr++;
    }
-
-   s.UngetWriteBuf();
 }
 
 static
index b8a8c1278273d8980c5a5d8cf1e79030fc7a9345..07e6e01cde7323eaf022940e3e8704a22dc6d920 100644 (file)
@@ -140,7 +140,8 @@ wxLayoutWindow::wxLayoutWindow(wxWindow *parent)
                                  wxDefaultPosition, wxDefaultSize,
                                  wxHSCROLL | wxVSCROLL |
                                  wxBORDER |
-                                 wxWANTS_CHARS)
+                                 wxWANTS_CHARS),
+                m_llist(NULL)
 {
    SetStatusBar(NULL); // don't use statusbar
    m_Editable = false;
@@ -156,14 +157,18 @@ wxLayoutWindow::wxLayoutWindow(wxWindow *parent)
    m_BGbitmap = NULL;
    m_ScrollToCursor = false;
    SetWrapMargin(0);
+
+   // initially the list is empty, so why would we need the scrollbars?
+#if 0
    wxPoint max = m_llist->GetSize();
    SetScrollbars(X_SCROLL_PAGE, Y_SCROLL_PAGE,
                  max.x / X_SCROLL_PAGE + 1, max.y / Y_SCROLL_PAGE + 1);
    EnableScrolling(true, true);
    m_maxx = max.x + X_SCROLL_PAGE;
    m_maxy = max.y + Y_SCROLL_PAGE;
+#endif // 0
 
-   // no scrollbars initially (BTW, why then we do all the stuff above?)
+   // no scrollbars initially
    m_hasHScrollbar =
    m_hasVScrollbar = false;
 
@@ -579,6 +584,18 @@ wxLayoutWindow::OnChar(wxKeyEvent& event)
                   m_llist->WrapLine(m_WrapMargin);
                m_llist->LineBreak();
                break;
+
+            case WXK_TAB:
+               {
+                   // TODO should be configurable
+                   static const int tabSize = 8;
+
+                   CoordType x = m_llist->GetCursorPos().x;
+                   size_t numSpaces = tabSize - x % tabSize;
+                   m_llist->Insert(wxString(' ', numSpaces));
+               }
+               break;
+
             default:
                if((!(event.ControlDown() || event.AltDown() || event.MetaDown()))
                   && (keyCode < 256 && keyCode >= 32)
@@ -640,19 +657,10 @@ wxLayoutWindow::ScrollToCursor(void)
    WXLO_DEBUG(("ScrollToCursor: ViewStart is %d/%d", x0, y0));
 
    // Get the size of the visible window:
-   GetClientSize(&x1,&y1);
-
-   // notice that the client size may be (0, 0)...
-   wxASSERT(x1 >= 0 && y1 >= 0);
+   GetClientSize(&x1, &y1);
 
-   // VZ: I think this is false - if you do it here, ResizeScrollbars() won't
-   //     call SetScrollbars() later
-#if 0
-   // As we have the values anyway, use them to avoid unnecessary scrollbar
-   // updates.
-   if(x1 > m_maxx) m_maxx = x1;
-   if(y1 > m_maxy) m_maxy = y1;
-#endif // 0
+   // update the cursor screen position
+   m_llist->Layout(dc);
 
    // Make sure that the scrollbars are at a position so that the cursor is
    // visible if we are editing
@@ -860,9 +868,12 @@ wxLayoutWindow::InternalPaint(const wxRect *updateRect)
 void
 wxLayoutWindow::OnSize(wxSizeEvent &event)
 {
-    ResizeScrollbars();
+   if ( m_llist )
+   {
+      ResizeScrollbars();
+   }
 
-    event.Skip();
+   event.Skip();
 }
 
 // change the range and position of scrollbars
index c936477bfee8ca56f3a9e9139c514638fd0f8832..7ed9994c80f50ffed3acb5e499ac08b4aad32f9a 100644 (file)
@@ -23,7 +23,7 @@
 #endif
 
 
-#define wxUSE_PRIVATE_CLIPBOARD_FORMAT 1
+#define wxUSE_PRIVATE_CLIPBOARD_FORMAT 0
 
 enum
 {