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