#OTHER by cg
authorClaus Gittinger <cg@exept.de>
Tue, 13 Sep 2016 15:49:35 +0200
changeset 5862 1f89188814b3
parent 5861 fb4a87d71c31
child 5863 65a6789689a3
#OTHER by cg class: ListView added: #updateWidthOfWidestLineFor: comment/format in: #documentation changed:7 methods dynamic widthOfContents update.
ListView.st
--- a/ListView.st	Tue Sep 13 15:23:10 2016 +0200
+++ b/ListView.st	Tue Sep 13 15:49:35 2016 +0200
@@ -79,23 +79,25 @@
 
     It can only scroll by full lines vertically (i.e. setting firstLineShown to ~~ 1)
     which should be changed to have this behavior optionally for smooth scroll.
-
+        
     The text is internally kept in the 'list' instance variable, and is supposed to consist
-    of a collection (Ordered- or StringCollection) of line entries.
+    of a collection (Ordered-, String- or VirtualCollection) of line entries.
     Typically, individual entries are either strings/text or nil (for empty lines).
     However, ANY object which supports the displayOn: and widthIn: protocol can be
     used - see MultipleColumnListEntry as an example.
     Therefore, ListView (and all subclasses) are prepared to handle non-string entries
     (especially: attributed Text and labelAndIcon-like entities).
 
-    The internal version of the text has tabulators expanded to blanks. ListView is not prepared
-    to deal with them. When text is exchanged with an external medium (i.e. reading/writing files),
+    The internal version of the text has tabulators expanded to blanks. 
+    ListView is not prepared to deal with them. 
+    When text is exchanged with an external medium (i.e. reading/writing files),
     these are expanded/compressed assuming a tab-setting of 8.
     This is done independent of the user's tab setting, which is used ONLY for positioning,
     while the text is edited.
     Thus, even if the tab setting is multiple of 4's, tabs are
-    written in multiples of 8 when the text is saved. Since this is the default on all ascii
-    terminals and printers, this assures that the text looks correctly indented when finally printed.
+    written in multiples of 8 when the text is saved. 
+    Since this is the default on all ascii terminals and printers, 
+    this assures that the text looks correctly indented when finally printed.
 
     Notice:
     -------
@@ -106,6 +108,7 @@
     views. The general scrolling code (in View) uses the transformation for transparent scrolling
     using the viewOrigin (transparent means, that the code does not need to know - it simply draws
     as if all of the text was visible).
+
     Here in ListView, the transformation is not used, instead it is done again, and different,
     by keeping the firstLineShown (i.e. vertical offset) and leftOffset (horizontal offset).
     Even worse: the firstLineShown is a line-index, the most annoying consequence of this is that
@@ -130,32 +133,36 @@
     In that, it performed *much* better than other widgets, especialy Java and Qt, some of which are
     hardly usable via the network.
     It may be questionable whether this is still a requirement these days, where network connections
-    are usually pretty fast. However, the author insists on this to remain as it is!!
+    are usually pretty fast. 
+    However, the author insists on this to remain as it is, because we do have customers
+    and applications which rely on relatively good remote display performance!!
     Future underlying graphics may well become network dependent in the future, for example, when
     the display connection is implemented as an RPC into a web browser...
 
-
-    Also Notice:
+    Also Notice (Virtual line collections):
     ------------
     ListView shall be configurable to avoid accesses to its underlying list if required.
     Currently, it can be customized to disable lineWidth computation, tab expansion and scanning for
-    non-string entries. All of which is required when huge texts which are not in memory are to be displayed
-    (for example: a virtual array of 10million text lines). Please be careful to not reintroduce such
-    code when adding features (as happened in the past).
-
+    non-string entries. 
+    All of which is required when huge texts which are not in memory are to be displayed
+    (for example: a virtual array of 10million text lines). 
+    Please be careful to not reintroduce such code when adding features 
+    (as happened in the past). ListView shall always be configurable to only access
+    a minimum subset of the line collection (i.e. only the currently visible page),
+    by customizing the tab-expansion, line-end and widthOfContents behavior.
 
     [Instance variables:]
 
       list                <aCollection>           the text strings, a collection of lines.
-						  Nils may be used for empty lines.
+                                                  Nils may be used for empty lines.
 
       firstLineShown      <Number>                the index of the 1st visible line (1 ..)
       leftOffset          <Number>                left offset for horizontal scroll
 
       nFullLinesShown     <Number>                the number of unclipped lines in visible area
-						  (internal; updated on size changes)
+                                                  (internal; updated on size changes)
       nLinesShown         <Number>                the number of lines in visible area, incl. partial
-						  (internal; updated on size changes)
+                                                  (internal; updated on size changes)
 
       fgColor             <Color>                 color to draw characters
       bgColor             <Color>                 the background
@@ -173,39 +180,39 @@
       fontWidth           <Number>                width of space (internal)
       lineSpacing         <Number>                pixels between lines
       lastSearchPattern   <String>                last pattern for searching
-						  (kept to provide a default for next search)
+                                                  (kept to provide a default for next search)
       lastSearchIgnoredCase   <Boolean>           last search ignored case
-						  (kept to provide a default for next search)
+                                                  (kept to provide a default for next search)
       wordCheck           <Block>                 rule used for check for word boundaries in word select
-						  The default rule is to return true for alphaNumeric characters.
-						  (can be changed to allow for underscore and other
-						   characters to be treated as alphaCharacters)
+                                                  The default rule is to return true for alphaNumeric characters.
+                                                  (can be changed to allow for underscore and other
+                                                   characters to be treated as alphaCharacters)
 
       autoScrollBlock     <Block>                 block installed as timeoutBlock when doing an
-						  autoScroll (internal)
+                                                  autoScroll (internal)
       autoScrollDeltaT                            computed scroll time delta in seconds (internal)
 
       includesNonStrings                          cached flag if any non-strings are in list
       widthOfWidestLine                           cached width of widest line
       listMsg                                     if view has a model and listMsg is non-nil,
-						  this is sent to the model to acquired a new contents
-						  whenever a change of the aspect  (aspectMsg) occurs.
+                                                  this is sent to the model to acquired a new contents
+                                                  whenever a change of the aspect  (aspectMsg) occurs.
 
       viewOrigin                                  the current origin
 
       backgroundAlreadyClearedColor               internal; speedup by avoiding
-						  multiple fills when drawing
-						  internal lines
+                                                  multiple fills when drawing
+                                                  internal lines
 
       scrollWhenUpdating
-				<Symbol>        defines how the view is scrolled if the
-						model changes its value by some outside activity
-						(i.e. not by user input).
-						Can be one of:
-						    #keep / nil     -> stay unchanged
-						    #endOfText      -> scroll to the end
-						    #beginOfText    -> scroll to the top
-						The default is #beginOfText (i.e. scroll to top).
+                                <Symbol>        defines how the view is scrolled if the
+                                                model changes its value by some outside activity
+                                                (i.e. not by user input).
+                                                Can be one of:
+                                                    #keep / nil     -> stay unchanged
+                                                    #endOfText      -> scroll to the end
+                                                    #beginOfText    -> scroll to the top
+                                                The default is #beginOfText (i.e. scroll to top).
 
     [StyleSheet parameters:]
 
@@ -215,10 +222,10 @@
       textTabPositions                            defaults to #(1 9 17 25 ...)
 
     [author:]
-	Claus Gittinger
+        Claus Gittinger
 
     [see also:]
-	TextView EditTextView
+        TextView EditTextView
 
 "
 !
@@ -1920,11 +1927,11 @@
     sH := lineSpacing // 2.
 
     backgroundAlreadyClearedColor == bg ifFalse:[
-	self paint:bg.
-	self fillRectangleX:margin
-			  y:y-sH
-		      width:(width - (margin * 2))
-		     height:(endVisLineNr - startVisLineNr + 1) * fontHeight + (lineSpacing - sH).
+        self paint:bg.
+        self fillRectangleX:margin
+                          y:y-sH
+                      width:(width - (margin * 2))
+                     height:(endVisLineNr - startVisLineNr + 1) * fontHeight + (lineSpacing - sH).
     ].
     list isNil ifTrue:[^ self].
 
@@ -1934,29 +1941,33 @@
     startLine := startVisLineNr + firstLineShown - 1.
     endLine := endVisLineNr + firstLineShown - 1.
     (startLine == 0) ifTrue:[
-	y := y + fontHeight.
-	startLine := startLine + 1
+        y := y + fontHeight.
+        startLine := startLine + 1
     ].
 
     (endLine > listSize) ifTrue:[
-	e := listSize
+        e := listSize
     ] ifFalse:[
-	e := endLine
+        e := endLine
     ].
 
     (startLine <= e) ifTrue:[
-	x := textStartLeft - viewOrigin x.
-	self paint:fg on:bg.
-	"/ don't use list from:to:do:, to allow for subclasses to redefine the enumeration (TableView)
-	self from:startLine to:e do:[:line |
-	    line notNil ifTrue:[
-		"/ remove line's color emphasis, to enforce color.
-		"/ otherwise blue text is not visible if selection-bg is blue
-		l := self withoutColorEmphasis:line ifFg:fg andBg:bg.
-		self displayOpaqueString:l x:x y:y
-	    ].
-	    y := y + fontHeight
-	]
+        x := textStartLeft - viewOrigin x.
+        self paint:fg on:bg.
+        "/ don't use list from:to:do:, to allow for subclasses to redefine the enumeration (TableView)
+        self from:startLine to:e do:[:line |
+            line notNil ifTrue:[
+                "/ remove line's color emphasis, to enforce color.
+                "/ otherwise blue text is not visible if selection-bg is blue
+                l := self withoutColorEmphasis:line ifFg:fg andBg:bg.
+                self displayOpaqueString:l x:x y:y.
+                
+                checkedLinesForWidthOfContentsComputation == 0 ifTrue:[
+                    self updateWidthOfWidestLineFor:l
+                ].    
+            ].
+            y := y + fontHeight
+        ]
     ]
 
     "Modified: / 15.12.1999 / 23:19:39 / cg"
@@ -1971,28 +1982,32 @@
 
     y := self yOfVisibleLine:visLineNr.
     backgroundAlreadyClearedColor == bg ifFalse:[
-	self paint:bg.
-	halfSpacing := (lineSpacing//2).
-	extraBelow := 0.
-	self highlightLineSpacing ifTrue:[
-	    extraBelow := halfSpacing.
-	].
-	self fillRectangleX:margin y:y - halfSpacing
-		      width:(width - (2 * margin))
-		     height:fontHeight+extraBelow.
+        self paint:bg.
+        halfSpacing := (lineSpacing//2).
+        extraBelow := 0.
+        self highlightLineSpacing ifTrue:[
+            extraBelow := halfSpacing.
+        ].
+        self fillRectangleX:margin y:y - halfSpacing
+                      width:(width - (2 * margin))
+                     height:fontHeight+extraBelow.
     ].
     line notNil ifTrue:[
-	self paint:fg on:bg.
-
-	"/ remove lines color emphasis, to enforce color.
-	"/ otherwise blue text is not visible if selection-bg is blue.
-	"/ this is only done in EditTextViews and subClasses.
-	self suppressEmphasisInSelection ifTrue:[
-	    l := self withoutColorEmphasis:line ifFg:fg andBg:bg.
-	] ifFalse:[
-	    l := line
-	].
-	self displayOpaqueString:l x:x y:(y + fontAscent)
+        self paint:fg on:bg.
+
+        "/ remove lines color emphasis, to enforce color.
+        "/ otherwise blue text is not visible if selection-bg is blue.
+        "/ this is only done in EditTextViews and subClasses.
+        self suppressEmphasisInSelection ifTrue:[
+            l := self withoutColorEmphasis:line ifFg:fg andBg:bg.
+        ] ifFalse:[
+            l := line
+        ].
+        self displayOpaqueString:l x:x y:(y + fontAscent).
+        
+        checkedLinesForWidthOfContentsComputation == 0 ifTrue:[
+            self updateWidthOfWidestLineFor:l
+        ].    
     ].
 
     "Modified: / 15.12.1999 / 23:19:46 / cg"
@@ -2007,12 +2022,16 @@
 
     y := self yOfVisibleLine:visLineNr.
     line notNil ifTrue:[
-	self paint:fg on:bg.
-
-	"/ remove lines color emphasis, to enforce color.
-	"/ otherwise blue text is not visible if selection-bg is blue
-	l := self withoutColorEmphasis:line ifFg:fg andBg:bg.
-	self displayOpaqueString:l x:x y:(y + fontAscent)
+        self paint:fg on:bg.
+
+        "/ remove lines color emphasis, to enforce color.
+        "/ otherwise blue text is not visible if selection-bg is blue
+        l := self withoutColorEmphasis:line ifFg:fg andBg:bg.
+        self displayOpaqueString:l x:x y:(y + fontAscent).
+        
+        checkedLinesForWidthOfContentsComputation == 0 ifTrue:[
+            self updateWidthOfWidestLineFor:l
+        ].    
     ]
 
     "Modified: / 15.12.1999 / 23:19:55 / cg"
@@ -2033,34 +2052,38 @@
     self paint:bg.
 
     (lineString notNil and:[lineString isString not]) ifTrue:[
-	w := lineString widthFrom:col to:(col min:len) on:self.
-	w <= 0 ifTrue:[
-	    w := gc font width.
-	    self fillRectangleX:x y:yf width:w height:fontHeight.
-	    self paint:fg
-	].
-	self clippedTo:(Rectangle left:x top:yf width:w height:fontHeight) do:[
-	    self drawVisibleLine:visLineNr with:fg and:bg
-	].
-	^ self
+        w := lineString widthFrom:col to:(col min:len) on:self.
+        w <= 0 ifTrue:[
+            w := gc font width.
+            self fillRectangleX:x y:yf width:w height:fontHeight.
+            self paint:fg
+        ].
+        self clippedTo:(Rectangle left:x top:yf width:w height:fontHeight) do:[
+            self drawVisibleLine:visLineNr with:fg and:bg
+        ].
+        ^ self
     ].
 
     (lineString isNil or:[col > len]) ifTrue:[
-	self fillRectangleX:x y:yf width:(gc font width) height:fontHeight.
-	self paint:fg
+        self fillRectangleX:x y:yf width:(gc font width) height:fontHeight.
+        self paint:fg
     ] ifFalse:[
-	characterString := lineString copyFrom:col to:col.
-
-	"/ remove lines color emphasis, to enforce color.
-	"/ otherwise blue text is not visible if selection-bg is blue
-	characterString := self withoutColorEmphasis:characterString ifFg:fg andBg:bg.
-	w := characterString widthOn:self.
-
-	self fillRectangleX:x y:yf width:w height:fontHeight.
-	self paint:fg.
-	self clippedTo:(Rectangle left:x top:yf width:w height:fontHeight) do:[
-	    self displayString:characterString x:x y:(y + fontAscent)
-	]
+        characterString := lineString copyFrom:col to:col.
+
+        "/ remove lines color emphasis, to enforce color.
+        "/ otherwise blue text is not visible if selection-bg is blue
+        characterString := self withoutColorEmphasis:characterString ifFg:fg andBg:bg.
+        w := characterString widthOn:self.
+
+        self fillRectangleX:x y:yf width:w height:fontHeight.
+        self paint:fg.
+        self clippedTo:(Rectangle left:x top:yf width:w height:fontHeight) do:[
+            self displayString:characterString x:x y:(y + fontAscent)
+        ].
+
+        checkedLinesForWidthOfContentsComputation == 0 ifTrue:[
+            self updateWidthOfWidestLineFor:characterString
+        ].    
     ]
 
     "Modified: / 15.12.1999 / 23:21:12 / cg"
@@ -2098,7 +2121,10 @@
             w > 0 ifTrue:[
                 self clippedTo:(Rectangle left:x top:yf width:w height:fontHeight) do:[
                     self drawVisibleLine:visLineNr with:fg and:bg.
-                ]
+                ].
+                checkedLinesForWidthOfContentsComputation == 0 ifTrue:[
+                    self updateWidthOfWidestLineFor:characterString
+                ].    
             ].
             ^ self.
         ].
@@ -2153,6 +2179,9 @@
                 "/ self displayOpaqueString:lineString from:sCol to:eCol x:x y:(y + fontAscent)
                 self displayString:lineString from:sCol to:eCol x:x y:(y + fontAscent) opaque:false maxWidth:self width
             ].
+            checkedLinesForWidthOfContentsComputation == 0 ifTrue:[
+                self updateWidthOfWidestLineFor:lineString
+            ].    
         ]
     ]
 
@@ -2165,31 +2194,35 @@
     |y x index1 index2 lineWithoutColor|
 
     (startCol < 1) ifTrue:[
-	index1 := 1
+        index1 := 1
     ] ifFalse:[
-	index1 := startCol
+        index1 := startCol
     ].
     y := self yOfVisibleLine:visLineNr.
     x := (self xOfCol:index1 inVisibleLine:visLineNr) - viewOrigin x.
     backgroundAlreadyClearedColor == bg ifFalse:[
-	self paint:bg.
-	self fillRectangleX:x y:y - (lineSpacing // 2)
-		      width:(width + viewOrigin x - x)
-		     height:fontHeight.
+        self paint:bg.
+        self fillRectangleX:x y:y - (lineSpacing // 2)
+                      width:(width + viewOrigin x - x)
+                     height:fontHeight.
     ].
     lineString notNil ifTrue:[
-	lineString isString ifFalse:[
-	    self drawLine:lineString inVisible:visLineNr from:startCol to:nil with:fg and:bg.
-	] ifTrue:[
-	    lineWithoutColor := self withoutColorEmphasis:lineString ifFg:fg andBg:bg.
-	    index2 := lineWithoutColor size.
-	    (index2 < index1) ifTrue:[^ self].
-	    (index1 <= index2) ifTrue:[
-		self paint:fg on:bg.
-		"/ self displayOpaqueString:lineWithoutColor from:index1 to:index2 x:x y:(y + fontAscent)
-		self displayString:lineWithoutColor from:index1 to:index2 x:x y:(y + fontAscent)
-	    ]
-	]
+        lineString isString ifFalse:[
+            self drawLine:lineString inVisible:visLineNr from:startCol to:nil with:fg and:bg.
+        ] ifTrue:[
+            lineWithoutColor := self withoutColorEmphasis:lineString ifFg:fg andBg:bg.
+            index2 := lineWithoutColor size.
+            (index2 < index1) ifTrue:[^ self].
+            (index1 <= index2) ifTrue:[
+                self paint:fg on:bg.
+                "/ self displayOpaqueString:lineWithoutColor from:index1 to:index2 x:x y:(y + fontAscent)
+                self displayString:lineWithoutColor from:index1 to:index2 x:x y:(y + fontAscent).
+
+                checkedLinesForWidthOfContentsComputation == 0 ifTrue:[
+                    self updateWidthOfWidestLineFor:lineWithoutColor
+                ].    
+            ]
+        ]
     ]
 
     "Modified: / 15.12.1999 / 23:24:40 / cg"
@@ -3130,6 +3163,18 @@
     "ignored here"
 !
 
+updateWidthOfWidestLineFor:aLine
+    "when set to do this dynamically
+     (eg when checkedLinesForWidthOfContentsComputation == 0)"
+
+    |w|
+
+    (w := self widthOfLine:aLine) > widthOfWidestLine ifTrue:[
+        widthOfWidestLine := w.
+        self contentsChanged.
+    ].    
+!
+
 visibleAt:visibleLineNr
     "return what is visible at line (numbers start at 1).
      This is used for redrawing; i.e. for non-string entries, this
@@ -3643,12 +3688,17 @@
         start := 1.
         stop := list size
     ] ifFalse:[
-        checkedLinesForWidthOfContentsComputation >= 0 ifTrue:[
-            start := 1.
-            stop := (checkedLinesForWidthOfContentsComputation min:list size)
-        ] ifFalse:[
-            stop := list size.
-            start := (list size + 1 + checkedLinesForWidthOfContentsComputation) max:1.
+        checkedLinesForWidthOfContentsComputation == 0 ifTrue:[
+            start := firstLineShown.
+            stop := start + nLinesShown - 1.
+        ] ifFalse:[    
+            checkedLinesForWidthOfContentsComputation > 0 ifTrue:[
+                start := 1.
+                stop := (checkedLinesForWidthOfContentsComputation min:list size)
+            ] ifFalse:[
+                stop := list size.
+                start := (list size + 1 + checkedLinesForWidthOfContentsComputation) max:1.
+            ]
         ]
     ].