]> icculus.org git repositories - duncan/yast2-qt4.git/blob - src/QY2DiskUsageList.cc
Duncan, for you
[duncan/yast2-qt4.git] / src / QY2DiskUsageList.cc
1 /*---------------------------------------------------------------------\
2 |                                                                      |
3 |                      __   __    ____ _____ ____                      |
4 |                      \ \ / /_ _/ ___|_   _|___ \                     |
5 |                       \ V / _` \___ \ | |   __) |                    |
6 |                        | | (_| |___) || |  / __/                     |
7 |                        |_|\__,_|____/ |_| |_____|                    |
8 |                                                                      |
9 |                               core system                            |
10 |                                                        (C) SuSE GmbH |
11 \----------------------------------------------------------------------/
12
13   File:       QY2DiskUsageList.cc
14
15   Author:     Stefan Hundhammer <sh@suse.de>
16
17   Textdomain "packages-qt"
18
19   This is a pure Qt widget - it can be used independently of YaST2.
20
21
22 /-*/
23
24 #include "QY2DiskUsageList.h"
25 #include "YQi18n.h"
26 #include <QPainter>
27
28
29 /**
30  * Stolen from KDirStat::KDirTreeView with the author's permission.
31  **/
32 QColor
33 contrastingColor( const QColor & desiredColor,
34                                         const QColor & contrastColor )
35 {
36     if ( desiredColor != contrastColor )
37     {
38         return desiredColor;
39     }
40
41     if ( contrastColor != contrastColor.light() )
42     {
43         // try a little lighter
44         return contrastColor.light();
45     }
46     else
47     {
48         // try a little darker
49         return contrastColor.dark();
50     }
51 }
52
53 /**
54  * Interpolate ( translate ) a value 'from' in the range between 'minFrom'
55  * and 'maxFrom'  to a range between 'minTo' and 'maxTo'.
56  **/
57 static int
58 interpolate( int from,
59                                    int minFrom, int maxFrom,
60                                    int minTo,   int maxTo       )
61 {
62     if ( minFrom > maxFrom )
63     {
64         // Swap min/max values
65
66         int tmp = maxFrom;
67         maxFrom = minFrom;
68         minFrom = tmp;
69     }
70
71     long x = from - minFrom;
72     x *= maxTo - minTo;
73     x /= maxFrom - minFrom;
74     x += minTo;
75
76     if ( minTo < maxTo )
77     {
78         if ( x < minTo )        x = minTo;
79         if ( x > maxTo )        x = maxTo;
80     }
81     else
82     {
83         if ( x < maxTo )        x = maxTo;
84         if ( x > minTo )        x = minTo;
85     }
86
87     return (int) x;
88 }
89
90 /**
91  * Interpolate ( in the HSV color space ) a color between 'minColor' and
92  * 'maxColor' for a current value 'val' so that 'minVal' corresponds to
93  * 'minColor' and 'maxVal' to 'maxColor'.
94  *
95  * Returns the interpolated color.
96  **/
97 static QColor
98 interpolateColor( int           val,
99                                         int             minVal,
100                                         int             maxVal,
101                                         const QColor &  minColor,
102                                         const QColor &  maxColor )
103 {
104     int minH, maxH;
105     int minS, maxS;
106     int minV, maxV;
107
108     minColor.getHsv( &minH, &minS, &minV );
109     maxColor.getHsv( &maxH, &maxS, &maxV );
110
111     return QColor::fromHsv( interpolate( val, minVal, maxVal, minH, maxH ),
112                    interpolate( val, minVal, maxVal, minS, maxS ),
113                    interpolate( val, minVal, maxVal, minV, maxV ) );
114 }
115
116
117 QY2DiskUsageList::QY2DiskUsageList( QWidget * parent, bool addStdColumns )
118     : QY2ListView( parent )
119 {
120     _nameCol            = -42;
121     _percentageBarCol   = -42;
122     _percentageCol      = -42;
123     _usedSizeCol        = -42;
124     _freeSizeCol        = -42;
125     _totalSizeCol       = -42;
126     _deviceNameCol      = -42;
127
128     QStringList columnLabels;
129     if ( addStdColumns )
130     {
131         int numCol = 0;
132         columnLabels << _( "Name"               );      _nameCol                = numCol++;
133         // Translators: Please keep this short!
134         columnLabels <<  _("Disk Usage");       _percentageBarCol       = numCol++;
135         columnLabels << ""; _percentageCol = numCol++;
136         columnLabels << _("Used"); _usedSizeCol         = numCol++;
137         columnLabels << _( "Free"); _freeSizeCol                = numCol++;
138         columnLabels << _("Total"); _totalSizeCol               = numCol++;
139 #if 0
140         addColumn( _( "Device"          ) );    _deviceNameCol          = numCol++;
141 #endif
142         // needed?
143         setColumnCount(numCol);
144         setHeaderLabels(columnLabels);
145         
146         //FIXME
147 //         setTextAlignment( percentageCol(), Qt::AlignRight );
148 //         setTextAlignment( usedSizeCol(), Qt::AlignRight );
149 //         setTextAlignment( freeSizeCol(), Qt::AlignRight );
150 //         setTextAlignment( totalSizeCol(), Qt::AlignRight );
151         sortItems( percentageBarCol(), Qt::AscendingOrder );
152     }
153
154     saveColumnWidths();
155     setSelectionMode(QAbstractItemView::NoSelection);
156 }
157
158
159 QY2DiskUsageList::~QY2DiskUsageList()
160 {
161 }
162
163
164 void QY2DiskUsageList::drawRow( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
165 {
166     if ( index.column() == percentageBarCol() )
167     {
168         QColor background = option.palette.color(QPalette::Base);
169         painter->setBackground( background );
170
171         QY2DiskUsageListItem *item = dynamic_cast<QY2DiskUsageListItem *>(itemFromIndex(index));
172         if ( item )
173         {
174           item->paintPercentageBar( item->usedPercent(),
175                                     painter,
176                                     option,
177                                     interpolateColor( item->usedPercent(),
178                                     60, 95,
179                                     QColor( 0, 0x80, 0 ),       // Medium dark green
180                                     QColor( 0xFF, 0, 0 ) ),     // Bright red
181                                     background.dark( 115 ) );
182        }
183     }
184     else
185     {
186         //QColorGroup cg( colorGroup );
187
188         //if ( usedSize() > totalSize() )
189         //  cg.setColor( QColorGroup::Text, Qt::red );          // Set red text foreground
190
191         // Intentionally bypassing the direct parent class method, use the grandparent's:
192         // Don't let QY2ListViewItem::_textColor / _backgroundColor interfere with our colors.
193
194         QTreeWidget::drawRow( painter, option, index );
195     }
196 }
197
198
199
200 QY2DiskUsageListItem::QY2DiskUsageListItem( QY2DiskUsageList * parent )
201     : QY2ListViewItem( parent )
202     , _diskUsageList( parent )
203 {
204 }
205
206
207
208
209 QY2DiskUsageListItem::~QY2DiskUsageListItem()
210 {
211     // NOP
212 }
213
214
215
216
217 void
218 QY2DiskUsageListItem::init( bool allFields )
219 {
220     if ( percentageCol()        >= 0 )
221     {
222         QString percentageText;
223         percentageText.sprintf( "%d%%", usedPercent() );
224         setText( percentageCol(), percentageText );
225     }
226
227     if ( usedSizeCol()          >= 0 ) setText( usedSizeCol(),          usedSize()      );
228     if ( freeSizeCol()          >= 0 ) setText( freeSizeCol(),          freeSize()      );
229
230     if ( allFields )
231     {
232         if ( totalSizeCol()     >= 0 ) setText( totalSizeCol(),         totalSize()     );
233         if ( nameCol()          >= 0 ) setText( nameCol(),              " " + name()    );
234         if ( deviceNameCol()    >= 0 ) setText( deviceNameCol(),        deviceName()    );
235     }
236 }
237
238
239 void
240 QY2DiskUsageListItem::setText( int column, const FSize & size )
241 {
242     QString sizeText = size.form( 0, 1, true ).c_str();
243     sizeText += " ";
244     setText( column, sizeText );
245 }
246
247
248 FSize
249 QY2DiskUsageListItem::freeSize() const
250 {
251     return totalSize() - usedSize();
252 }
253
254
255 int
256 QY2DiskUsageListItem::usedPercent() const
257 {
258     int percent = 0;
259
260     if ( totalSize() != 0 )
261         percent = ( 100 * usedSize() ) / totalSize();
262
263     return percent;
264 }
265
266
267 void
268 QY2DiskUsageListItem::updateStatus()
269 {
270     init( false );
271 }
272
273
274 void
275 QY2DiskUsageListItem::updateData()
276 {
277     init( true );
278 }
279
280
281
282
283
284 /**
285  * Comparison function used for sorting the list.
286  * Returns:
287  * -1 if this <  other
288  *  0 if this == other
289  * +1 if this >  other
290  **/
291 int
292 QY2DiskUsageListItem::compare( QTreeWidgetItem *        otherListViewItem,
293                                int              col,
294                                bool             ascending ) const
295 {
296     QY2DiskUsageListItem * other = dynamic_cast<QY2DiskUsageListItem *> (otherListViewItem);
297
298     if ( other )
299     {
300         if ( col == percentageCol()    ||
301              col == percentageBarCol()   )
302         {
303             // Intentionally reverting sort order: Fullest first
304
305             if ( this->usedPercent() < other->usedPercent() )   return  1;
306             if ( this->usedPercent() > other->usedPercent() )   return -1;
307             return 0;
308         }
309         else if ( col == usedSizeCol() )
310         {
311             if ( this->usedSize() < other->usedSize() )         return -1;
312             if ( this->usedSize() > other->usedSize() )         return  1;
313             return 0;
314         }
315         else if ( col == freeSizeCol() )
316         {
317             if ( this->freeSize() < other->freeSize() )         return -1;
318             if ( this->freeSize() > other->freeSize() )         return  1;
319             return 0;
320         }
321         else if ( col == totalSizeCol() )
322         {
323             if ( this->totalSize() < other->totalSize() )       return -1;
324             if ( this->totalSize() > other->totalSize() )       return  1;
325             return 0;
326         }
327     }
328
329     return QY2ListViewItem::compare( otherListViewItem, col, ascending );
330 }
331
332 /**
333  * Stolen from KDirStat::KDirTreeView with the author's permission.
334  **/
335 void
336 QY2DiskUsageListItem::paintPercentageBar( float                 percent,
337                                           QPainter *            painter,
338                                           QStyleOptionViewItem option,
339                                           const QColor &        fillColor,
340                                           const QColor &        barBackground )
341 {
342      if ( percent > 100.0 )     percent = 100.0;
343      if ( percent < 0.0   )     percent = 0.0;
344      int penWidth = 2;
345      int extraMargin = 3;
346      int x = 0; /*FIXME _diskUsageList->itemMargin(); */
347      int y = extraMargin;
348      int w = option.rect.width()    - 2; /*FIXME * _diskUsageList->horizontalOffset(); */
349      int h = option.rect.height() - 2; /*FIXME * extraMargin; */
350      int fillWidth;
351  
352      painter->eraseRect( 0, 0, option.rect.width(), option.rect.height() );
353      int indent=0;
354      w -= indent;
355      x += indent;
356  
357      if ( w > 0 )
358      {
359         QPen pen( painter->pen() );
360         pen.setWidth(0);
361         painter->setPen( pen );
362         painter->setBrush( Qt::NoBrush );
363         fillWidth = (int) ( ( w - 2 * penWidth ) * percent / 100.0 );
364  
365  
366         // Fill bar background.
367  
368         painter->fillRect( x + penWidth, y + penWidth,
369                            w - 2 * penWidth + 1, h - 2 * penWidth + 1,
370                            barBackground );
371         /*
372          * Notice: The Xlib XDrawRectangle() function always fills one
373          * pixel less than specified. Altough this is very likely just a
374          * plain old bug, it is documented that way. Obviously, Qt just
375          * maps the fillRect() call directly to XDrawRectangle() so they
376          * inherited that bug ( although the Qt doc stays silent about
377          * it ). So it is really necessary to compensate for that missing
378          * pixel in each dimension.
379          *
380          * If you don't believe it, see for yourself.
381          * Hint: Try the xmag program to zoom into the drawn pixels.
382          **/
383
384         // Fill the desired percentage.
385
386         painter->fillRect( x + penWidth, y + penWidth,
387                            fillWidth+1, h - 2 * penWidth+1,
388                            fillColor );
389
390
391         // Draw 3D shadows.
392
393         pen.setColor( contrastingColor ( Qt::black,
394                                          painter->background().color() ) );
395         painter->setPen( pen );
396         painter->drawLine( x, y, x+w, y );
397         painter->drawLine( x, y, x, y+h );
398
399         pen.setColor( contrastingColor( barBackground.dark(),
400                                         painter->background().color() ) );
401         painter->setPen( pen );
402         painter->drawLine( x+1, y+1, x+w-1, y+1 );
403         painter->drawLine( x+1, y+1, x+1, y+h-1 );
404
405         pen.setColor( contrastingColor( barBackground.light(),
406                                         painter->background().color() ) );
407         painter->setPen( pen );
408         painter->drawLine( x+1, y+h, x+w, y+h );
409         painter->drawLine( x+w, y, x+w, y+h );
410
411         pen.setColor( contrastingColor( Qt::white,
412                                         painter->background().color() ) );
413         painter->setPen( pen );
414         painter->drawLine( x+2, y+h-1, x+w-1, y+h-1 );
415         painter->drawLine( x+w-1, y+1, x+w-1, y+h-1 );
416    }
417 }
418
419
420
421
422
423 #include "QY2DiskUsageList.moc"