DataSetColumn.st
author james
Thu, 26 Sep 2002 10:42:29 +0200
changeset 2221 19a1500f8113
parent 2211 f14db8e094b9
child 2222 c1349adf1329
permissions -rw-r--r--
write to a column no longer installs the return value of a colAdaptor as new row object. Must see if that creates problems in any existing app.

"
 COPYRIGHT (c) 1997 by Claus Gittinger / eXept Software AG
              All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"




"{ Package: 'stx:libwidg2' }"

Object subclass:#DataSetColumn
	instanceVariableNames:'columnNumber dataSet width description buttonExtent shownValue
		rendererType backgroundColor foregroundColor rowSeparatorSelector
		showColSeparator showRowSeparator columnAlignment label
		containsText columnAdaptor descWidth descMinWidth
		longStringCompression'
	classVariableNames:''
	poolDictionaries:''
	category:'Views-DataSet'
!

!DataSetColumn class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1997 by Claus Gittinger / eXept Software AG
              All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"



!

documentation
"
    represent one single column description of a DataSetView

    [Instance variables:]

        columnNumber    <Integer>               sequence number (into list of columns)

        dataSet         <DSVColumnView>         the view it belongs to

        width           <Integer>               width of column

        description     <DataSetColumnSpec>     the column description

        buttonExtent    <Point>                 extent of drawable form

        rendererType    <Type>                  renderer type (cached value from
                                                the column specification).

        backgroundColor <Color or nil>          background color of all cells or nil
                                                (nil: use default background color).

        foregroundColor <Color or nil>          foreground color of all cells or nil
                                                (nil: use default foreground color).

        columnAlignment <Symbol>                align text/icon #left #right or #center
                                                in row (on default: #left).

        label           <label/icon or nil>     label resolved by the builder shown
                                                in the column description field.

        readSelector    <Symbol>                cached readSelector (from the spec)

        columnAdaptor   <nil or any>            if non-nil, that one is asked (via
                                                read-writeSelectors to extract a column
                                                from a row object.
                                                If nil, the row object is used itself.

        showColSeparator <Boolean>              true: vertical separators are enabled;
                                                separator between columns

        showRowSeparator <Boolean>              true: horizontal separators are enabled;
                                                separator between rows

        rowSeparatorSelector <Selector or nil>  access specific showRowSeparator state
                                                for a cell

    [from description:]
        fgSelector      <Selector or nil>       access specific foreground color for
                                                a cell

        bgSelector      <Selector or nil>       access specific background color for
                                                a cell

        numberOfRowsProbedForColumnSize         the number of rows which are queries
                                <Integer>       in order to compute the columns width.
                                                (for scrollBar/col width computation)
                                                Notice, if its expensive to fetch rows
                                                (dataBase apps), this should be small.
                                                Default:15


    [author:]
        Claus Atzkern

    [see also:]
        DataSetColumnSpec
        DSVColumnView
        DataSetView
"
! !

!DataSetColumn class methodsFor:'utilities'!

shortenedStringFor:aString on:aGC maxWidth:maxWidth
    "common code to shorten a string; used in both the DSV label- and column Views,  
     if the string is too long for the column"

    |widthOf3Dots wRest shortenedLabel lUsed lMin lMax|

    aString isString ifFalse:[^ aString].
    (aString widthOn:aGC) > maxWidth ifFalse:[aString].

    widthOf3Dots := '...' widthOn:aGC.

    lMin := 1.
    lMax := aString size.
    [ 
        lUsed := (lMax + lMin) // 2.
        wRest := aString widthFrom:1 to:lUsed on:aGC.
        wRest > (maxWidth-widthOf3Dots) ifTrue:[
            lMax := lUsed - 1.
        ] ifFalse:[
            lMin := lUsed + 1.
        ].
        lMin < lMax
    ] whileTrue.
    shortenedLabel := aString copyFrom:1 to:lUsed.

    shortenedLabel isEmpty ifTrue:[
        ((aString first asString , '..') widthOn:aGC) < maxWidth ifTrue:[
            "/ only two dots and the first character
            ^ (aString first asString , '..')
        ]
    ].
    ^ (shortenedLabel , '...').
! !

!DataSetColumn methodsFor:'accessing'!

at:aRowNr
    "get the value of the raw at an index, aRowNr
    "

    |row|

    row := dataSet at:aRowNr.
    ^ self extractColFromRow:row rowNr:aRowNr.
!

at:aRowNr put:something
    "set the value of the raw at an index, aRowNr
    "
    |row newRow|

    row := dataSet at:aRowNr.
    self storeCol:something inRow:row.
!

columnAdaptor
    ^ columnAdaptor
!

columnAdaptor:anAdapter
    columnAdaptor := anAdapter.
!

description
    "returns the column description
    "
    ^ description


!

label
    "get the label assigned to the column
    "
    ^ label


!

rendererType
    "returns my renderer type
    "
    ^ rendererType
! !

!DataSetColumn methodsFor:'accessing-colors'!

backgroundColor
    "returns the background color or nil
    "
    ^ backgroundColor == dataSet backgroundColor ifTrue:[nil]
                                                ifFalse:[backgroundColor]

!

backgroundColorAt:aRowNr
    "returns the background color for a row at list index a rowNr
    "
    description backgroundSelector notNil ifTrue:[
        ^ self backgroundColorFor:(dataSet at:aRowNr) at:aRowNr
    ].
    ^ backgroundColor
!

backgroundColorFor:aRow at:aRowNr     
    "returns the background color for a row at list index a rowNr
    "
    |bgSelector bg|

    bgSelector := description backgroundSelector.
    bgSelector notNil ifTrue:[
        columnAdaptor notNil ifTrue:[
            bg := columnAdaptor perform:bgSelector withOptionalArgument:aRow and:aRowNr and:columnNumber and:dataSet
        ] ifFalse:[
            bg := aRow perform:bgSelector withOptionalArgument:aRowNr and:columnNumber and:dataSet
        ].
        bg notNil ifTrue:[
            (bg isColor or:[bg isImageOrForm]) ifTrue:[
                ^ bg
            ].
            self halt:'unexpected bg (not color or image)'.
        ]
    ].
    ^ backgroundColor
!

foregroundColor
    "returns the foreground color or nil
    "
    ^ foregroundColor == dataSet foregroundColor ifTrue:[nil]
                                                ifFalse:[foregroundColor]

!

foregroundColorFor:aRow at:aRowNr
    "returns the foreground color for a row at list index a rowNr
    "
    |fgSelector fg|

    fgSelector := description foregroundSelector.
    fgSelector notNil ifTrue:[
        columnAdaptor notNil ifTrue:[
            fg := columnAdaptor perform:fgSelector withOptionalArgument:aRow and:aRowNr and:columnNumber and:dataSet
        ] ifFalse:[
            fg := aRow perform:fgSelector withOptionalArgument:aRowNr and:dataSet
        ].
        fg notNil ifTrue:[
            (fg isColor or:[fg isImageOrForm]) ifTrue:[
                ^ fg
            ].
            self halt:'unexpected fg (not color or image)'.
        ]
    ].
    ^ foregroundColor
! !

!DataSetColumn methodsFor:'accessing-dimension'!

minWidth
    "get the minimum width required by the column
    "
    descMinWidth notNil ifTrue:[
        ^ descMinWidth
    ].
    width := nil.
  ^ self width

!

minimumRequiredWidth
    "returns the minimum required width
    "
    |minWidth|

    descMinWidth notNil ifTrue:[
        minWidth := DSVLabelView tabSpacing max:2.
      ^ minWidth // 2 + minWidth
    ].

    minWidth := dataSet separatorSize + (2 * dataSet horizontalSpacing).
  ^ minWidth + label preferredWidth.
!

setDescWidth:aWidth
    "set a fixed width
    "
    descMinWidth := 1.
    descMinWidth := width := descWidth := self minimumRequiredWidth max:aWidth.
!

width
    "returns the width in pixels
     Warning: 
        only the first numberOfRowsProbedForColumnSize are probed,
        in case the access is expensive (dataBase apps)
     If the descriptor defines a width, that is used, and the items
     are not probed at all."

    |max       "{ Class:SmallInteger }"
     listSize  "{ Class:SmallInteger }"|

    width notNil ifTrue:[^ width].              "/ already computed

    descMinWidth notNil ifTrue:[
        width := descMinWidth.
      ^ width
    ].

    (descWidth ~~ 0 and:[descWidth isLimitedPrecisionReal not]) ifTrue:[
        width := descMinWidth := descWidth.
      ^ width
    ].

    width := description minWidth max:(label preferredWidth).

    descWidth isLimitedPrecisionReal ifTrue:[
        width := width max:(descWidth * dataSet innerWidth) rounded.
      ^ width
    ].

    containsText ifTrue:[
        "/ take maximum numberOfRowsProbedForColumnSize entries to calculate the width;
        "/ can be resized later if neccessary
        listSize := dataSet size.
        max := listSize min:description numberOfRowsProbedForColumnSize.

        max ~~ 0 ifTrue:[
            1 to:max do:[:rowNr| |row|
                row := dataSet at:rowNr.
                width := width max:(self widthOfLabel:(shownValue value:row value:rowNr))
            ].
            width := width max:(self widthOfLabel:(shownValue value:(dataSet at:listSize) value:listSize))
        ].
        description editorType ~~ #None ifTrue:[
            width := width + (dataSet font widthOn:dataSet device)
        ].
    ] ifFalse:[
        max := 1
    ].
    width := width + buttonExtent x + dataSet separatorSize + (2 * dataSet horizontalSpacing).

    max ~~ 0 ifTrue:[
        descMinWidth := width.
        description usePreferredWidth ifTrue:[
            descWidth := width
        ]
    ].
  ^ width

    "Modified: / 25.2.2000 / 14:29:16 / cg"
! !

!DataSetColumn methodsFor:'drawing'!

drawLabel:aLabelToDraw atX:xLeft y:yTop
    "redraw label
    "
    |drawnLabel x space prevClip mustUndoClip labelWidth|

    space := dataSet horizontalSpacing.

    drawnLabel := aLabelToDraw.
    labelWidth := drawnLabel widthOn:dataSet.

    ("longStringCompression notNil" true
    and:[ drawnLabel isString 
    and:[ labelWidth > width]]) ifTrue:[
        drawnLabel := self class shortenedStringFor:drawnLabel on:dataSet maxWidth:width-space.
        labelWidth := drawnLabel widthOn:dataSet.
    ].

    columnAlignment == #left ifTrue:[
        x  := xLeft + space.
    ] ifFalse:[
        x := width - labelWidth.

        columnAlignment == #right ifTrue:[x := x - space]
                                 ifFalse:[x := x // 2].

"/ cg: old code (did not right-align if string is larger than width
"/        x := xLeft + (x max:0).

        "/ new code: always right-align.
        x := xLeft + x.

        "/ must clip left, if string is too large
        x < xLeft ifTrue:[
            "/ must clip ...
            prevClip := dataSet clippingRectangleOrNil.
            mustUndoClip := true.
            dataSet clippingRectangle:(Rectangle 
                                left:xLeft top:yTop 
                                width:width height:(drawnLabel heightOn:dataSet)).
        ].
    ].

    drawnLabel isImageOrForm ifTrue:[
        drawnLabel displayOn:dataSet x:x y:yTop.
    ] ifFalse:[
        drawnLabel displayOn:dataSet x:x y:(yTop + dataSet rowFontAscent)
    ].

    mustUndoClip == true ifTrue:[
        dataSet clippingRectangle:prevClip    
    ].
!

drawLabelsAtX:xLeft y:yTop h:h from:start to:stop
    "redraw labels from start to stop
    "
    |fg bg label row isSel
     y       "{ Class:SmallInteger }"
     yT      "{ Class:SmallInteger }"
     x       "{ Class:SmallInteger }"
     hspace  "{ Class:SmallInteger }"
     ascent  "{ Class:SmallInteger }"
     lblHg   "{ Class:SmallInteger }"
    |
    yT := yTop.
    ascent := dataSet rowFontAscent.
    hspace := dataSet horizontalSpacing.

    start to:stop do:[:aRowNr|
        row := dataSet at:aRowNr.
        y := yT.
        x := xLeft.

     "/ GET BACKGROUND AND FOREGROUND-COLOR
     "/ ===================================

        isSel := dataSet isSelected:aRowNr inColumn:columnNumber.

        isSel ifTrue:[
            (      description editorType ~~ #None
              and:[dataSet selectedColIndex == columnNumber]
            ) ifTrue:[
                isSel := false
            ]
        ].

        (isSel and:[description showSelectionHighLighted]) ifTrue:[
            "/ SHOW SELECTED( MUST REDRAW BACKGROUND )
            "/ =======================================
            fg := dataSet selectionForegroundColor.
            bg := dataSet selectionBackgroundColor.
            dataSet paint:bg.
            dataSet fillRectangleX:x y:y width:width height:h.
        ] ifFalse:[
            description backgroundSelector notNil ifTrue:[
                "/ MUST REDRAW BACKGROUND
                "/ ======================
                bg := self backgroundColorFor:row at:aRowNr.

                bg ~~ backgroundColor ifTrue:[
                    bg := dataSet colorOnDevice:bg
                ].
                dataSet paint:bg.
                dataSet fillRectangleX:x y:y width:width height:h.
            ] ifFalse:[
                bg := backgroundColor
            ].

            fg := self foregroundColorFor:row at:aRowNr.

            fg ~~ foregroundColor ifTrue:[
                fg := dataSet colorOnDevice:fg
            ].
        ].

     "/ GET AND DRAW LABEL
     "/ ==================
        rendererType == #rowSelector ifTrue:[
            isSel ifTrue:[
                label := dataSet rowSelectorForm.
                x  := x + hspace.
            ] ifFalse:[
                label := nil
            ]
        ] ifFalse:[
            (isSel and:[dataSet hasOpenEditor]) ifTrue:[
                label := nil
            ]  ifFalse:[
                label := shownValue value:row value:aRowNr
            ]
        ].
        label notNil ifTrue:[
            "/ care for a dark-colored label,
            "/ with a dark selection-bg color
            (isSel and:[label isString and:[label hasChangeOfEmphasis]]) ifTrue:[
                "/ take away the labels own color info
                label := label emphasisAllRemove:#color.
            ].

            lblHg := self heightOfLabel:label.

            lblHg ~~ 0 ifTrue:[
                y := y + (h - lblHg // 2).
                dataSet paint:fg on:bg.

                (label isSequenceable and:[label isString not]) ifFalse:[
                    self drawLabel:label atX:x y:y
                ] ifTrue:[
                    label do:[:el|
                        el notNil ifTrue:[
                            self drawLabel:el atX:x y:y.
                            y := y + (el heightOn:dataSet).
                        ]
                    ]
                ].
            ]
        ].
        yT := yT + h
    ]
!

drawSeparatorsAtX:xLeft y:yTop h:h from:start to:stop
    "redraw separators for cells between start and stop
    "
    |is3D
     xL    "{ Class:SmallInteger }"
     xR    "{ Class:SmallInteger }"
     yB    "{ Class:SmallInteger }"
     yT    "{ Class:SmallInteger }"
     times "{ Class:SmallInteger }"
    |
    (showColSeparator or:[showRowSeparator]) ifFalse:[
        ^ self
    ].
    is3D := dataSet has3Dseparators.

    is3D ifTrue:[dataSet paint:(dataSet separatorDarkColor)]
        ifFalse:[dataSet paint:(dataSet foregroundColor)].

    times := stop - start + 1.
    xL    := xLeft.
    xR    := xL - 1 + width.

    showRowSeparator ifTrue:[
     "/ DRAW SEPARATORS AT BOTTOM( DARK COLOR )
     "/ =======================================
        yB := yTop - 1 + h.

        rowSeparatorSelector isNil ifTrue:[
            times timesRepeat:[
                dataSet displayLineFromX:xL y:yB toX:xR y:yB.
                yB := yB + h.
            ]
        ] ifFalse:[
            start to:stop do:[:idx|
                ((dataSet at:idx) perform:rowSeparatorSelector) ~~ false ifTrue:[
                    dataSet displayLineFromX:xL y:yB toX:xR y:yB
                ].
                yB := yB + h.
            ]
        ]
    ].

    showColSeparator ifTrue:[
     "/ DRAW SEPARATORS AT RIGHT( DARK COLOR )
     "/ ======================================
        yT := yTop.

        times timesRepeat:[
            dataSet displayLineFromX:xR y:yT toX:xR y:(yT - 1 + h).
            yT := yT + h.
        ]
    ].

    is3D ifFalse:[
        ^ self
    ].

    dataSet paint:(dataSet separatorLightColor).

    (     columnNumber == 1
      or:[(dataSet columnAt:(columnNumber - 1)) showColSeparator]
    ) ifTrue:[

     "/ DRAW SEPARATORS AT LEFT( LIGHT COLOR )
     "/ ======================================
        yT := yTop.

        times timesRepeat:[
            dataSet displayLineFromX:xL y:yT toX:xL y:(yT - 1 + h).
            yT := yT + h.
        ].
    ] ifFalse:[
        xL := xL - 1
    ].

    showRowSeparator ifTrue:[
     "/ DRAW SEPARATORS AT TOP( LIGHT COLOR )
     "/ =====================================
        yT := yTop.

        rowSeparatorSelector isNil ifTrue:[
            times timesRepeat:[
                dataSet displayLineFromX:xL y:yT toX:xR y:yT.
                yT := yT + h.
            ]
        ] ifFalse:[
         "/ CHECK WHETHER PREVIOUS ROW HAS A SEPARATOR AT BOTTOM
         "/ ====================================================
            start to:stop do:[:idx|
                (    idx == 1
                  or:[((dataSet at:(idx - 1)) perform:rowSeparatorSelector) ~~ false]
                ) ifTrue:[
                    dataSet displayLineFromX:xL y:yT toX:xR y:yT.
                ].
                yT := yT + h.
            ]
        ]
    ].


!

invalidate
    "invalidate width of column; forces a recomputation
    "
    width := nil.

!

redrawX:xLeft y:yTop h:h from:start to:stop
    "redraw rows between start and stop
    "
    |rH "{ Class:SmallInteger }"
     y  "{ Class:SmallInteger }"
    |
    rH := dataSet rowHeight.

    description backgroundSelector isNil ifTrue:[
        dataSet paint:backgroundColor.
        dataSet fillRectangleX:xLeft y:yTop width:width height:h
    ].

 "/ DRAW CELLS: BACKGROUND/FOREGROUND/LABEL
 "/ =======================================
    self drawLabelsAtX:xLeft y:yTop h:rH from:start to:stop.

 "/ DRAW INDICATORS
 "/ ===============
    (rendererType == #ComboBox or:[rendererType == #ComboList]) ifTrue:[
        y := yTop.
        start to:stop do:[:rowNr|
            (self hasChoices:rowNr) ifTrue:[
                dataSet drawComboButtonAtX:xLeft y:y w:width
            ].
            y := y + rH.
        ]
    ] ifFalse:[
        rendererType == #CheckToggle ifTrue:[
            y := yTop.
            start to:stop do:[:rowNr| |state|
                state := self at:rowNr.
                dataSet drawCheckToggleAtX:xLeft y:y w:width state:state.
                y := y + rH.
            ]
        ]
    ].

 "/ DRAW SEPARATORS
 "/ ===============
    self drawSeparatorsAtX:xLeft y:yTop h:rH from:start to:stop
! !

!DataSetColumn methodsFor:'editing'!

editorAt:aRowNr
    |val row|

    row := (dataSet at:aRowNr).
    val := self extractColFromRow:row rowNr:aRowNr.

    val isText ifTrue:[val := val string].
    ^ description editorOn:row column:self value:val usingAdaptor:columnAdaptor.
! !

!DataSetColumn methodsFor:'event handling'!

doesNotUnderstand:aMessage

    (description respondsTo:(aMessage selector)) ifTrue:[
        ^ aMessage sendTo:description
    ].
    ^ super doesNotUnderstand:aMessage

! !

!DataSetColumn methodsFor:'grow & degrow'!

growWidth:n
    "grow the width for n pixels
    "
    width := self width + n.


! !

!DataSetColumn methodsFor:'initialization'!

on:aDSVColumnView description:aDescription columnNumber:aNumber label:aLabel
    "instance creation; set attributes dependent on the description
    "
    |device selector format idx type|

    columnNumber     := aNumber.
    dataSet          := aDSVColumnView.
    label            := aLabel.

    description      := aDescription.
    rendererType     := description rendererType.
    containsText     := (      rendererType ~~ #CheckToggle
                          and:[rendererType ~~ #rowSelector]
                        ).
    descWidth        := description width.

    description usePreferredWidth ifTrue:[
        descWidth := 0
    ].

    width      := nil.
    device     := dataSet device.
    shownValue := [:aRow :aRowNr| nil ].

    rowSeparatorSelector := description rowSeparatorSelector.

    showColSeparator := description showColSeparator.
    showRowSeparator := description showRowSeparator.
    columnAdaptor    := dataSet columnAdaptor.
    buttonExtent     := 0 @ 0.
    columnAlignment  := #left.

    (backgroundColor := description backgroundColor) isNil ifTrue:[
        backgroundColor := dataSet backgroundColor
    ] ifFalse:[
        backgroundColor := backgroundColor onDevice:dataSet device
    ].

    (foregroundColor := description foregroundColor) isNil ifTrue:[
        foregroundColor := dataSet foregroundColor
    ] ifFalse:[
        foregroundColor := foregroundColor onDevice:dataSet device
    ].

    rendererType == #CheckToggle ifTrue:[
        buttonExtent := dataSet checkToggleExtent.
        ^ self
    ].

    rendererType == #rowSelector ifTrue:[
        buttonExtent := dataSet rowSelectorExtent.
        ^ self
    ].

    (rendererType == #ComboBox or:[rendererType == #ComboList]) ifTrue:[
        buttonExtent := dataSet comboButtonExtent.
    ] ifFalse:[
        columnAlignment := description columnAlignment
    ].

    selector := description printSelector.

    selector notNil ifTrue:[
        shownValue := [:aRow :aRowNr| aRow perform:selector withOptionalArgument:dataSet and:columnNumber and:aRowNr and:dataSet].
        ^ self
    ].

    (     (format := description formatString) notNil
     and:[(type   := description type) == #number or:[type == #numberOrNil]]
    ) ifTrue:[
        "/ has a format string for number (supports only floats)

        (idx := format indexOf:$.) ~~ 0 ifTrue:[
            idx := format size - idx
        ].
        format := '%0.', idx printString, 'f'.

        shownValue := [:aRow :aRowNr| |n|
            n := self extractColFromRow:aRow rowNr:aRowNr.
            n isLimitedPrecisionReal ifTrue:[n := n asFloat printfPrintString:format].
            n
        ]
    ] ifFalse:[         "/ default: no format string
        shownValue := [:aRow :aRowNr| self extractColFromRow:aRow rowNr:aRowNr ]
    ]

    "Modified: / 25.2.2000 / 14:25:56 / cg"
! !

!DataSetColumn methodsFor:'private'!

extractColFromRow:aRow rowNr:rowNr
    |readSelector|

    readSelector := description readSelector.
    readSelector isNil ifTrue:[^ nil].

    columnAdaptor notNil ifTrue:[
        ^ columnAdaptor perform:readSelector withOptionalArgument:aRow and:columnNumber and:rowNr and:dataSet
    ].
    ^ aRow perform:readSelector withOptionalArgument:columnNumber and:rowNr and:dataSet
!

storeCol:newValue inRow:aRow
    |writeSelector numArgs|

    writeSelector := description writeSelector.
    writeSelector isNil ifTrue:[^ aRow].

    numArgs := writeSelector numArgs.

    columnAdaptor notNil ifTrue:[
        numArgs == 2 ifTrue:[
            columnAdaptor perform:writeSelector with:aRow with:newValue.
            ^ self
        ].
        columnAdaptor perform:writeSelector with:aRow with:columnNumber with:newValue.
        ^ self
    ].

    numArgs == 1 ifTrue:[
        aRow perform:writeSelector with:newValue
    ] ifFalse:[
        aRow perform:writeSelector with:columnNumber with:newValue
    ].

! !

!DataSetColumn methodsFor:'queries'!

canResize

    containsText ifTrue:[
        ^ descWidth == 0 or:[self hasRelativeWidth]
    ].
    ^ false
!

canSelect:aRowNr
    "returns true if the cell in column is selectable
    "
    |s row|

    description canSelect ifFalse:[^ false].
    s := description selectSelector.
    s isNil ifTrue:[^ true].

    row := dataSet at:aRowNr.
    columnAdaptor notNil ifTrue:[
        ^ columnAdaptor perform:s withOptionalArgument:row and:columnNumber and:aRowNr and:dataSet
    ].

    ^ row perform:s withOptionalArgument:columnNumber and:aRowNr and:dataSet
!

containsText
    "returns true if text might exist
    "
    ^ containsText
!

doubleClickOn:aRowNr
    |sel|

    (sel := self doubleClickedSelector) notNil ifTrue:[
        columnAdaptor notNil ifTrue:[
            sel numArgs == 2 ifTrue:[
                ^ columnAdaptor perform:sel with:(dataSet at:aRowNr) with:columnNumber
            ].
            ^ columnAdaptor perform:sel with:(dataSet at:aRowNr)
        ].
        sel numArgs == 1 ifTrue:[
            ^ (dataSet at:aRowNr) perform:sel with:columnNumber
        ].
        ^ (dataSet at:aRowNr) perform:sel
    ].
!

hasChoices:aRowNr
    ^ (description choicesFor:(dataSet at:aRowNr)) notNil
!

hasPotentialNonConstantBackground
    (backgroundColor notNil and:[backgroundColor isImageOrForm]) ifTrue:[^ true].
    description backgroundSelector notNil ifTrue:[^ true].
    ^ false.
!

hasRelativeWidth
    "returns true if width is relative
    "
    ^ descWidth isLimitedPrecisionReal 
!

heightOfHighestRow
    "returns the height of the highest row in pixels.
     Warning: 
        only the first numberOfRowsProbedForColumnSize are probed,
        in case the access is expensive (dataBase apps)
     If the descriptor defines a height, that is used, and the items
     are not probed at all.
    "
    |h end bE editor|

    (h := description height) == 0 ifTrue:[
        containsText ifTrue:[
            "/ search first none empty drawable object
            end := description numberOfRowsProbedForColumnSize min:dataSet size.

            1 to:end do:[:rowNr| |row|
                row := dataSet at:rowNr.
                h := h max:(self heightOfLabel:(shownValue value:row value:rowNr))
            ]
        ]
    ].
    (bE := buttonExtent y) = 0 ifTrue:[
        ((editor := description editorType) == #ComboList
        or:[ editor  == #ComboBox]) ifTrue:[
            bE := dataSet comboButtonExtent y.
        ].
    ].
    ^ h max:bE

    "Modified: / 25.2.2000 / 14:29:20 / cg"
!

heightOfLabel:aLabel
    "returns the height of the label
    "
    |h|

    (aLabel isString or:[aLabel isImageOrForm]) ifTrue:[
        ^ aLabel heightOn:dataSet
    ].
    aLabel isNil ifTrue:[ ^ 0 ].

    aLabel isSequenceable ifFalse:[
        ^  aLabel perform:#heightOn: with:dataSet ifNotUnderstood:[
                aLabel displayString heightOn:dataSet
           ]
    ].

    h := 0.
    aLabel do:[:el|h := h + (el heightOn:dataSet)].
  ^ h

!

isResizeable
    "returns true if the row is resizeable
    "
    ^ description isResizeable
!

showColSeparator
    "returns true if column separator is on
    "
    ^ showColSeparator
!

showSelectionHighLighted
    "returns true if selection is highLighted
    "
    ^ description showSelectionHighLighted ~~ false
!

widthOfLabel:aLabel
    "returns the width of the label
    "
    |w|

    (aLabel isString or:[aLabel isImageOrForm]) ifTrue:[
        ^ aLabel widthOn:dataSet
    ].
    aLabel isNil ifTrue:[ ^ 0 ].

    aLabel isSequenceable ifFalse:[
        ^  aLabel perform:#widthOn: with:dataSet ifNotUnderstood:[
                aLabel displayString widthOn:dataSet
           ]
    ].

    w := 0.
    aLabel do:[:el|w := w max:(el widthOn:dataSet)].
  ^ w
! !

!DataSetColumn methodsFor:'searching'!

findRowNrStartingWithChar:aChar start:start stop:stop
    "find the first row starting at start to stop, which drawable label
     starts with the character, aChar. The index of the detected row is
     returned or if no row is found 0.
    "
    |char|

    containsText ifTrue:[
        char  := aChar asLowercase.

        start to:stop do:[:eachNr| |row lbl|
            row := dataSet at:eachNr.
            lbl := shownValue value:row value:eachNr.

            (lbl isSequenceable and:[lbl isString not]) ifTrue:[
                lbl := lbl at:1 ifAbsent:nil
            ].

            (lbl respondsTo:#string) ifTrue:[
                lbl := lbl string.
                (lbl size ~~ 0 and:[(lbl at:1) asLowercase == char]) ifTrue:[
                    ^ eachNr
                ]
            ] ifFalse:[
                lbl isNil ifFalse:[
                    ^ 0
                ]
            ]
        ]
    ].
    ^ 0
! !

!DataSetColumn class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libwidg2/DataSetColumn.st,v 1.78 2002-09-26 08:42:29 james Exp $'
! !