1 /*
2 * File name: FilesystemsWindow.cpp
3 * Summary: QDirStat "Mounted Filesystems" window
4 * License: GPL V2 - See file LICENSE for details.
5 *
6 * Author: Stefan Hundhammer <Stefan.Hundhammer@gmx.de>
7 */
8
9
10 #include <QFileIconProvider>
11
12 #include "FilesystemsWindow.h"
13 #include "MountPoints.h"
14 #include "SettingsHelpers.h"
15 #include "HeaderTweaker.h"
16 #include "PanelMessage.h"
17 #include "FormatUtil.h"
18 #include "Logger.h"
19 #include "Exception.h"
20
21 #define WARN_PERCENT 10.0
22
23 using namespace QDirStat;
24
25
FilesystemsWindow(QWidget * parent)26 FilesystemsWindow::FilesystemsWindow( QWidget * parent ):
27 QDialog( parent ),
28 _ui( new Ui::FilesystemsWindow )
29 {
30 CHECK_NEW( _ui );
31 _ui->setupUi( this );
32 MountPoints::reload();
33 initWidgets();
34 readWindowSettings( this, "FilesystemsWindow" );
35 }
36
37
~FilesystemsWindow()38 FilesystemsWindow::~FilesystemsWindow()
39 {
40 writeWindowSettings( this, "FilesystemsWindow" );
41 delete _ui;
42 }
43
44
populate()45 void FilesystemsWindow::populate()
46 {
47 QFileIconProvider iconProvider;
48 clear();
49
50 foreach ( MountPoint * mountPoint, MountPoints::normalMountPoints() )
51 {
52 CHECK_PTR( mountPoint);
53
54 if ( mountPoint->isUnmountedAutofs() )
55 continue;
56
57 FilesystemItem * item = new FilesystemItem( mountPoint, _ui->fsTree );
58 CHECK_NEW( item );
59
60 QIcon icon = iconProvider.icon( mountPoint->isNetworkMount() ?
61 QFileIconProvider::Network :
62 QFileIconProvider::Drive );
63 item->setIcon( 0, icon );
64 }
65
66 if ( MountPoints::hasBtrfs() )
67 showBtrfsFreeSizeWarning();
68 }
69
70
showBtrfsFreeSizeWarning()71 void FilesystemsWindow::showBtrfsFreeSizeWarning()
72 {
73 PanelMessage * msg = new PanelMessage( _ui->messagePanel );
74 CHECK_NEW( msg );
75
76 msg->setHeading( tr( "Btrfs free and used size information are misleading!" ) );
77 msg->setText( tr( "Snapshots and copy-on-write may consume additional disk space." ) );
78 msg->setDetailsUrl( "https://github.com/shundhammer/qdirstat/blob/master/doc/Btrfs-Free-Size.md" );
79 _ui->messagePanel->add( msg );
80 }
81
82
refresh()83 void FilesystemsWindow::refresh()
84 {
85 MountPoints::reload();
86 populate();
87 }
88
89
reject()90 void FilesystemsWindow::reject()
91 {
92 deleteLater();
93 }
94
95
clear()96 void FilesystemsWindow::clear()
97 {
98 _ui->fsTree->clear();
99 _ui->messagePanel->clear();
100 }
101
102
initWidgets()103 void FilesystemsWindow::initWidgets()
104 {
105 QStringList headers;
106 headers << tr( "Device" )
107 << tr( "Mount Point" )
108 << tr( "Type" );
109
110 if ( MountPoints::hasSizeInfo() )
111 {
112 headers << tr( "Size" )
113 << tr( "Used" )
114 << tr( "Reserved" )
115 << tr( "Free" )
116 << tr( "Free %" );
117 }
118
119 _ui->fsTree->setHeaderLabels( headers );
120 _ui->fsTree->header()->setStretchLastSection( false );
121
122 // Center the column headers
123
124 QTreeWidgetItem * hItem = _ui->fsTree->headerItem();
125
126 for ( int col = 0; col < headers.size(); ++col )
127 hItem->setTextAlignment( col, Qt::AlignHCenter );
128
129 hItem->setToolTip( FS_ReservedSizeCol, tr( "Reserved for root" ) );
130 hItem->setToolTip( FS_FreeSizeCol, tr( "Free for unprivileged users" ) );
131
132 HeaderTweaker::resizeToContents( _ui->fsTree->header() );
133 _ui->fsTree->sortItems( FS_DeviceCol, Qt::AscendingOrder );
134 enableActions();
135
136 connect( _ui->refreshButton, SIGNAL( clicked() ),
137 this, SLOT ( refresh() ) );
138
139 connect( _ui->readButton, SIGNAL( clicked() ),
140 this, SLOT ( readSelectedFilesystem() ) );
141
142 connect( _ui->fsTree, SIGNAL( itemSelectionChanged() ),
143 this, SLOT ( enableActions() ) );
144 }
145
146
enableActions()147 void FilesystemsWindow::enableActions()
148 {
149 _ui->readButton->setEnabled( ! selectedPath().isEmpty() );
150 }
151
152
readSelectedFilesystem()153 void FilesystemsWindow::readSelectedFilesystem()
154 {
155 QString path = selectedPath();
156
157 if ( ! path.isEmpty() )
158 {
159 logDebug() << "Read " << path << endl;
160 emit readFilesystem( path );
161 }
162 }
163
164
selectedPath() const165 QString FilesystemsWindow::selectedPath() const
166 {
167 QString result;
168 QList<QTreeWidgetItem *> sel = _ui->fsTree->selectedItems();
169
170 if ( ! sel.isEmpty() )
171 {
172 FilesystemItem * item = dynamic_cast<FilesystemItem *>( sel.first() );
173
174 if ( item )
175 result = item->mountPath();
176 }
177
178 return result;
179 }
180
181
182
183
FilesystemItem(MountPoint * mountPoint,QTreeWidget * parent)184 FilesystemItem::FilesystemItem( MountPoint * mountPoint,
185 QTreeWidget * parent ):
186 QTreeWidgetItem( parent ),
187 _device ( mountPoint->device() ),
188 _mountPath ( mountPoint->path() ),
189 _fsType ( mountPoint->filesystemType() ),
190 _totalSize ( mountPoint->totalSize() ),
191 _usedSize ( mountPoint->usedSize() ),
192 _reservedSize ( mountPoint->reservedSize() ),
193 _freeSize ( mountPoint->freeSizeForUser() ),
194 _isNetworkMount ( mountPoint->isNetworkMount() ),
195 _isReadOnly ( mountPoint->isReadOnly() )
196 {
197 QString blanks = QString( 4, ' ' );
198
199 setText( FS_DeviceCol, _device + blanks );
200 setText( FS_MountPathCol, _mountPath );
201 setText( FS_TypeCol, _fsType );
202
203 setTextAlignment( FS_TypeCol, Qt::AlignHCenter );
204
205 if ( parent->columnCount() >= FS_TotalSizeCol && _totalSize >= 0 )
206 {
207 blanks = QString( 3, ' ' ); // Enforce left margin
208
209 setText( FS_TotalSizeCol, blanks + formatSize( _totalSize ) );
210 setText( FS_UsedSizeCol, blanks + formatSize( _usedSize ) );
211
212 if ( _reservedSize > 0 )
213 setText( FS_ReservedSizeCol, blanks + formatSize( _reservedSize ) );
214
215 if ( _isReadOnly )
216 setText( FS_FreeSizeCol, QObject::tr( "read-only" ) );
217 else
218 {
219 setText( FS_FreeSizeCol, blanks + formatSize( _freeSize ) );
220
221 float freePercent = 0.0;
222
223 if ( _totalSize > 0 )
224 {
225 freePercent = 100.0 * _freeSize / _totalSize;
226 setText( FS_FreePercentCol, formatPercent( freePercent ) );
227
228 if ( freePercent < WARN_PERCENT )
229 {
230 setForeground( FS_FreeSizeCol, Qt::red );
231 setForeground( FS_FreePercentCol, Qt::red );
232 }
233 }
234 }
235
236 for ( int col = FS_TotalSizeCol; col < parent->columnCount(); ++col )
237 setTextAlignment( col, Qt::AlignRight );
238 }
239 }
240
241
operator <(const QTreeWidgetItem & rawOther) const242 bool FilesystemItem::operator<( const QTreeWidgetItem & rawOther ) const
243 {
244 const FilesystemItem & other = dynamic_cast<const FilesystemItem &>( rawOther );
245
246 int col = treeWidget() ? treeWidget()->sortColumn() : FS_DeviceCol;
247
248 switch ( col )
249 {
250 case FS_DeviceCol:
251 if ( ! isNetworkMount() && other.isNetworkMount() ) return true;
252 if ( isNetworkMount() && ! other.isNetworkMount() ) return false;
253 return device() < other.device();
254
255 case FS_MountPathCol: return mountPath() < other.mountPath();
256 case FS_TypeCol: return fsType() < other.fsType();
257 case FS_TotalSizeCol: return totalSize() < other.totalSize();
258 case FS_UsedSizeCol: return usedSize() < other.usedSize();
259 case FS_ReservedSizeCol: return reservedSize() < other.reservedSize();
260 case FS_FreePercentCol:
261 case FS_FreeSizeCol: return freeSize() < other.freeSize();
262 default: return QTreeWidgetItem::operator<( rawOther );
263 }
264 }
265