QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
qgssvgselectorwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssvgselectorwidget.cpp - group and preview selector for SVG files
3  built off of work in qgssymbollayerv2widget
4 
5  ---------------------
6  begin : April 2, 2013
7  copyright : (C) 2013 by Larry Shaffer
8  email : larrys at dakcarto dot com
9  ***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 #include "qgssvgselectorwidget.h"
18 
19 #include "qgsapplication.h"
20 #include "qgslogger.h"
21 #include "qgsproject.h"
22 #include "qgssvgcache.h"
23 #include "qgssymbollayerv2utils.h"
24 
25 #include <QAbstractListModel>
26 #include <QCheckBox>
27 #include <QDir>
28 #include <QFileDialog>
29 #include <QModelIndex>
30 #include <QPixmapCache>
31 #include <QSettings>
32 #include <QStyle>
33 #include <QTime>
34 
35 // QgsSvgSelectorLoader
36 
38 QgsSvgSelectorLoader::QgsSvgSelectorLoader( QObject* parent )
39  : QThread( parent )
40  , mCancelled( false )
41  , mTimerThreshold( 0 )
42 {
43 }
44 
45 QgsSvgSelectorLoader::~QgsSvgSelectorLoader()
46 {
47  stop();
48 }
49 
50 void QgsSvgSelectorLoader::run()
51 {
52  mCancelled = false;
53  mQueuedSvgs.clear();
54  mTraversedPaths.clear();
55 
56  // start with a small initial timeout (ms)
57  mTimerThreshold = 10;
58  mTimer.start();
59 
60  loadPath( mPath );
61 
62  if ( !mQueuedSvgs.isEmpty() )
63  {
64  // make sure we notify model of any remaining queued svgs (ie svgs added since last foundSvgs() signal was emitted)
65  emit foundSvgs( mQueuedSvgs );
66  }
67  mQueuedSvgs.clear();
68 }
69 
70 void QgsSvgSelectorLoader::stop()
71 {
72  mCancelled = true;
73  while ( isRunning() ) {}
74 }
75 
76 void QgsSvgSelectorLoader::loadPath( const QString& path )
77 {
78  if ( mCancelled )
79  return;
80 
81  // QgsDebugMsg( QString( "loading path: %1" ).arg( path ) );
82 
83  if ( path.isEmpty() )
84  {
86  Q_FOREACH ( const QString& svgPath, svgPaths )
87  {
88  if ( mCancelled )
89  return;
90 
91  if ( !svgPath.isEmpty() )
92  {
93  loadPath( svgPath );
94  }
95  }
96  }
97  else
98  {
99  QDir dir( path );
100 
101  //guard against circular symbolic links
102  QString canonicalPath = dir.canonicalPath();
103  if ( mTraversedPaths.contains( canonicalPath ) )
104  return;
105 
106  mTraversedPaths.insert( canonicalPath );
107 
108  loadImages( path );
109 
110  Q_FOREACH ( const QString& item, dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
111  {
112  if ( mCancelled )
113  return;
114 
115  QString newPath = dir.path() + '/' + item;
116  loadPath( newPath );
117  // QgsDebugMsg( QString( "added path: %1" ).arg( newPath ) );
118  }
119  }
120 }
121 
122 void QgsSvgSelectorLoader::loadImages( const QString& path )
123 {
124  QDir dir( path );
125  Q_FOREACH ( const QString& item, dir.entryList( QStringList( "*.svg" ), QDir::Files ) )
126  {
127  if ( mCancelled )
128  return;
129 
130  // TODO test if it is correct SVG
131  QString svgPath = dir.path() + '/' + item;
132  // QgsDebugMsg( QString( "adding svg: %1" ).arg( svgPath ) );
133 
134  // add it to the list of queued SVGs
135  mQueuedSvgs << svgPath;
136 
137  // we need to avoid spamming the model with notifications about new svgs, so foundSvgs
138  // is only emitted for blocks of SVGs (otherwise the view goes all flickery)
139  if ( mTimer.elapsed() > mTimerThreshold && !mQueuedSvgs.isEmpty() )
140  {
141  emit foundSvgs( mQueuedSvgs );
142  mQueuedSvgs.clear();
143 
144  // increase the timer threshold - this ensures that the first lots of svgs loaded are added
145  // to the view quickly, but as the list grows new svgs are added at a slower rate.
146  // ie, good for initial responsiveness but avoid being spammy as the list grows.
147  if ( mTimerThreshold < 1000 )
148  mTimerThreshold *= 2;
149  mTimer.restart();
150  }
151  }
152 }
153 
154 
155 //
156 // QgsSvgGroupLoader
157 //
158 
159 QgsSvgGroupLoader::QgsSvgGroupLoader( QObject* parent )
160  : QThread( parent )
161  , mCancelled( false )
162 {
163 
164 }
165 
166 QgsSvgGroupLoader::~QgsSvgGroupLoader()
167 {
168  stop();
169 }
170 
171 void QgsSvgGroupLoader::run()
172 {
173  mCancelled = false;
174  mTraversedPaths.clear();
175 
176  while ( !mCancelled && !mParentPaths.isEmpty() )
177  {
178  QString parentPath = mParentPaths.takeFirst();
179  loadGroup( parentPath );
180  }
181 }
182 
183 void QgsSvgGroupLoader::stop()
184 {
185  mCancelled = true;
186  while ( isRunning() ) {}
187 }
188 
189 void QgsSvgGroupLoader::loadGroup( const QString& parentPath )
190 {
191  QDir parentDir( parentPath );
192 
193  //guard against circular symbolic links
194  QString canonicalPath = parentDir.canonicalPath();
195  if ( mTraversedPaths.contains( canonicalPath ) )
196  return;
197 
198  mTraversedPaths.insert( canonicalPath );
199 
200  Q_FOREACH ( const QString& item, parentDir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ) )
201  {
202  if ( mCancelled )
203  return;
204 
205  emit foundPath( parentPath, item );
206  mParentPaths.append( parentDir.path() + '/' + item );
207  }
208 }
209 
211 
212 //,
213 // QgsSvgSelectorListModel
214 //
215 
217  : QAbstractListModel( parent )
218  , mSvgLoader( new QgsSvgSelectorLoader( this ) )
219 {
220  mSvgLoader->setPath( QString() );
221  connect( mSvgLoader, SIGNAL( foundSvgs( QStringList ) ), this, SLOT( addSvgs( QStringList ) ) );
222  mSvgLoader->start();
223 }
224 
226  : QAbstractListModel( parent )
227  , mSvgLoader( new QgsSvgSelectorLoader( this ) )
228 {
229  mSvgLoader->setPath( path );
230  connect( mSvgLoader, SIGNAL( foundSvgs( QStringList ) ), this, SLOT( addSvgs( QStringList ) ) );
231  mSvgLoader->start();
232 }
233 
235 {
236  Q_UNUSED( parent );
237  return mSvgFiles.count();
238 }
239 
240 QPixmap QgsSvgSelectorListModel::createPreview( const QString& entry ) const
241 {
242  // render SVG file
243  QColor fill, outline;
244  double outlineWidth, fillOpacity, outlineOpacity;
245  bool fillParam, fillOpacityParam, outlineParam, outlineWidthParam, outlineOpacityParam;
246  bool hasDefaultFillColor = false, hasDefaultFillOpacity = false, hasDefaultOutlineColor = false,
247  hasDefaultOutlineWidth = false, hasDefaultOutlineOpacity = false;
248  QgsSvgCache::instance()->containsParams( entry, fillParam, hasDefaultFillColor, fill,
249  fillOpacityParam, hasDefaultFillOpacity, fillOpacity,
250  outlineParam, hasDefaultOutlineColor, outline,
251  outlineWidthParam, hasDefaultOutlineWidth, outlineWidth,
252  outlineOpacityParam, hasDefaultOutlineOpacity, outlineOpacity );
253 
254  //if defaults not set in symbol, use these values
255  if ( !hasDefaultFillColor )
256  fill = QColor( 200, 200, 200 );
257  fill.setAlphaF( hasDefaultFillOpacity ? fillOpacity : 1.0 );
258  if ( !hasDefaultOutlineColor )
259  outline = Qt::black;
260  outline.setAlphaF( hasDefaultOutlineOpacity ? outlineOpacity : 1.0 );
261  if ( !hasDefaultOutlineWidth )
262  outlineWidth = 0.2;
263 
264  bool fitsInCache; // should always fit in cache at these sizes (i.e. under 559 px ^ 2, or half cache size)
265  const QImage& img = QgsSvgCache::instance()->svgAsImage( entry, 30.0, fill, outline, outlineWidth, 3.5 /*appr. 88 dpi*/, 1.0, fitsInCache );
266  return QPixmap::fromImage( img );
267 }
268 
270 {
271  QString entry = mSvgFiles.at( index.row() );
272 
273  if ( role == Qt::DecorationRole ) // icon
274  {
275  QPixmap pixmap;
276  if ( !QPixmapCache::find( entry, pixmap ) )
277  {
278  pixmap = createPreview( entry );
279  QPixmapCache::insert( entry, pixmap );
280  }
281 
282  return pixmap;
283  }
284  else if ( role == Qt::UserRole || role == Qt::ToolTipRole )
285  {
286  return entry;
287  }
288 
289  return QVariant();
290 }
291 
292 void QgsSvgSelectorListModel::addSvgs( const QStringList& svgs )
293 {
295  mSvgFiles.append( svgs );
296  endInsertRows();
297 }
298 
299 
300 
301 
302 
303 //--- QgsSvgSelectorGroupsModel
304 
306  : QStandardItemModel( parent )
307  , mLoader( new QgsSvgGroupLoader( this ) )
308 {
310  QStandardItem *parentItem = invisibleRootItem();
311  QStringList parentPaths;
312 
313  for ( int i = 0; i < svgPaths.size(); i++ )
314  {
315  QDir dir( svgPaths.at( i ) );
316  QStandardItem *baseGroup;
317 
318  if ( dir.path().contains( QgsApplication::pkgDataPath() ) )
319  {
320  baseGroup = new QStandardItem( tr( "App Symbols" ) );
321  }
322  else if ( dir.path().contains( QgsApplication::qgisSettingsDirPath() ) )
323  {
324  baseGroup = new QStandardItem( tr( "User Symbols" ) );
325  }
326  else
327  {
328  baseGroup = new QStandardItem( dir.dirName() );
329  }
330  baseGroup->setData( QVariant( svgPaths.at( i ) ) );
331  baseGroup->setEditable( false );
332  baseGroup->setCheckable( false );
333  baseGroup->setIcon( QgsApplication::style()->standardIcon( QStyle::SP_DirIcon ) );
334  baseGroup->setToolTip( dir.path() );
335  parentItem->appendRow( baseGroup );
336  parentPaths << svgPaths.at( i );
337  mPathItemHash.insert( svgPaths.at( i ), baseGroup );
338  QgsDebugMsg( QString( "SVG base path %1: %2" ).arg( i ).arg( baseGroup->data().toString() ) );
339  }
340  mLoader->setParentPaths( parentPaths );
341  connect( mLoader, SIGNAL( foundPath( QString, QString ) ), this, SLOT( addPath( QString, QString ) ) );
342  mLoader->start();
343 }
344 
346 {
347  mLoader->stop();
348 }
349 
350 void QgsSvgSelectorGroupsModel::addPath( const QString& parentPath, const QString& item )
351 {
352  QStandardItem* parentGroup = mPathItemHash.value( parentPath );
353  if ( !parentGroup )
354  return;
355 
356  QString fullPath = parentPath + '/' + item;
357  QStandardItem* group = new QStandardItem( item );
358  group->setData( QVariant( fullPath ) );
359  group->setEditable( false );
360  group->setCheckable( false );
361  group->setToolTip( fullPath );
362  group->setIcon( QgsApplication::style()->standardIcon( QStyle::SP_DirIcon ) );
363  parentGroup->appendRow( group );
364  mPathItemHash.insert( fullPath, group );
365 }
366 
367 
368 //-- QgsSvgSelectorWidget
369 
371  : QWidget( parent )
372 {
373  // TODO: in-code gui setup with option to vertically or horizontally stack SVG groups/images widgets
374  setupUi( this );
375 
376  mGroupsTreeView->setHeaderHidden( true );
377  populateList();
378 
379  connect( mImagesListView->selectionModel(), SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ),
380  this, SLOT( svgSelectionChanged( const QModelIndex& ) ) );
381  connect( mGroupsTreeView->selectionModel(), SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ),
382  this, SLOT( populateIcons( const QModelIndex& ) ) );
383 
384  QSettings settings;
385  bool useRelativePath = ( QgsProject::instance()->readBoolEntry( "Paths", "/Absolute", false )
386  || settings.value( "/Windows/SvgSelectorWidget/RelativePath" ).toBool() );
387  mRelativePathChkBx->setChecked( useRelativePath );
388 }
389 
391 {
392  QSettings settings;
393  settings.setValue( "/Windows/SvgSelectorWidget/RelativePath", mRelativePathChkBx->isChecked() );
394 }
395 
397 {
398  QString updatedPath( "" );
399 
400  // skip possible urls, excepting those that may locally resolve
401  if ( !svgPath.contains( "://" ) || ( svgPath.contains( "file://", Qt::CaseInsensitive ) ) )
402  {
403  QString resolvedPath = QgsSymbolLayerV2Utils::symbolNameToPath( svgPath.trimmed() );
404  if ( !resolvedPath.isNull() )
405  {
406  updatedPath = resolvedPath;
407  }
408  }
409 
410  mCurrentSvgPath = updatedPath;
411 
412  mFileLineEdit->blockSignals( true );
413  mFileLineEdit->setText( updatedPath );
414  mFileLineEdit->blockSignals( false );
415 
416  mImagesListView->selectionModel()->blockSignals( true );
417  QAbstractItemModel* m = mImagesListView->model();
418  QItemSelectionModel* selModel = mImagesListView->selectionModel();
419  for ( int i = 0; i < m->rowCount(); i++ )
420  {
421  QModelIndex idx( m->index( i, 0 ) );
422  if ( m->data( idx ).toString() == svgPath )
423  {
424  selModel->select( idx, QItemSelectionModel::SelectCurrent );
425  selModel->setCurrentIndex( idx, QItemSelectionModel::SelectCurrent );
426  mImagesListView->scrollTo( idx );
427  break;
428  }
429  }
430  mImagesListView->selectionModel()->blockSignals( false );
431 }
432 
434 {
435  if ( mRelativePathChkBx->isChecked() )
436  return currentSvgPathToName();
437 
438  return mCurrentSvgPath;
439 }
440 
442 {
443  return QgsSymbolLayerV2Utils::symbolPathToName( mCurrentSvgPath );
444 }
445 
446 void QgsSvgSelectorWidget::updateCurrentSvgPath( const QString& svgPath )
447 {
448  mCurrentSvgPath = svgPath;
449  emit svgSelected( currentSvgPath() );
450 }
451 
452 void QgsSvgSelectorWidget::svgSelectionChanged( const QModelIndex& idx )
453 {
454  QString filePath = idx.data( Qt::UserRole ).toString();
455  mFileLineEdit->setText( filePath );
456  updateCurrentSvgPath( filePath );
457 }
458 
459 void QgsSvgSelectorWidget::populateIcons( const QModelIndex& idx )
460 {
461  QString path = idx.data( Qt::UserRole + 1 ).toString();
462 
463  QAbstractItemModel* oldModel = mImagesListView->model();
464  QgsSvgSelectorListModel* m = new QgsSvgSelectorListModel( mImagesListView, path );
465  mImagesListView->setModel( m );
466  delete oldModel; //explicitly delete old model to force any background threads to stop
467 
468  connect( mImagesListView->selectionModel(), SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ),
469  this, SLOT( svgSelectionChanged( const QModelIndex& ) ) );
470 
471 }
472 
473 void QgsSvgSelectorWidget::on_mFilePushButton_clicked()
474 {
475  QSettings settings;
476  QString openDir = settings.value( "/UI/lastSVGMarkerDir", QDir::homePath() ).toString();
477 
478  QString lineEditText = mFileLineEdit->text();
479  if ( !lineEditText.isEmpty() )
480  {
481  QFileInfo openDirFileInfo( lineEditText );
482  openDir = openDirFileInfo.path();
483  }
484 
485  QString file = QFileDialog::getOpenFileName( nullptr,
486  tr( "Select SVG file" ),
487  openDir,
488  tr( "SVG files" ) + " (*.svg *.SVG)" );
489 
490  activateWindow(); // return window focus
491 
492  if ( file.isNull() )
493  return;
494 
495  QFileInfo fi( file );
496  if ( !fi.exists() || !fi.isReadable() )
497  {
498  updateCurrentSvgPath( QString() );
499  updateLineEditFeedback( false );
500  return;
501  }
502  settings.setValue( "/UI/lastSVGMarkerDir", fi.absolutePath() );
503  mFileLineEdit->setText( file );
504  updateCurrentSvgPath( file );
505 }
506 
507 void QgsSvgSelectorWidget::updateLineEditFeedback( bool ok, const QString& tip )
508 {
509  // draw red text for path field if invalid (path can't be resolved)
510  mFileLineEdit->setStyleSheet( QString( !ok ? "QLineEdit{ color: rgb(225, 0, 0); }" : "" ) );
511  mFileLineEdit->setToolTip( !ok ? tr( "File not found" ) : tip );
512 }
513 
514 void QgsSvgSelectorWidget::on_mFileLineEdit_textChanged( const QString& text )
515 {
516  QString resolvedPath = QgsSymbolLayerV2Utils::symbolNameToPath( text );
517  bool validSVG = !resolvedPath.isNull();
518 
519  updateLineEditFeedback( validSVG, resolvedPath );
520  updateCurrentSvgPath( validSVG ? resolvedPath : QString() );
521 }
522 
524 {
525  QgsSvgSelectorGroupsModel* g = new QgsSvgSelectorGroupsModel( mGroupsTreeView );
526  mGroupsTreeView->setModel( g );
527  // Set the tree expanded at the first level
528  int rows = g->rowCount( g->indexFromItem( g->invisibleRootItem() ) );
529  for ( int i = 0; i < rows; i++ )
530  {
531  mGroupsTreeView->setExpanded( g->indexFromItem( g->item( i ) ), true );
532  }
533 
534  // Initally load the icons in the List view without any grouping
535  QAbstractItemModel* oldModel = mImagesListView->model();
536  QgsSvgSelectorListModel* m = new QgsSvgSelectorListModel( mImagesListView );
537  mImagesListView->setModel( m );
538  delete oldModel; //explicitly delete old model to force any background threads to stop
539 }
540 
541 //-- QgsSvgSelectorDialog
542 
544  const QDialogButtonBox::StandardButtons& buttons,
545  Qt::Orientation orientation )
546  : QDialog( parent, fl )
547 {
548  // TODO: pass 'orientation' to QgsSvgSelectorWidget for customizing its layout, once implemented
549  Q_UNUSED( orientation );
550 
551  // create buttonbox
552  mButtonBox = new QDialogButtonBox( buttons, orientation, this );
553  connect( mButtonBox, SIGNAL( accepted() ), this, SLOT( accept() ) );
554  connect( mButtonBox, SIGNAL( rejected() ), this, SLOT( reject() ) );
555 
556  setMinimumSize( 480, 320 );
557 
558  // dialog's layout
559  mLayout = new QVBoxLayout();
560  mSvgSelector = new QgsSvgSelectorWidget( this );
562 
564  setLayout( mLayout );
565 
566  QSettings settings;
567  restoreGeometry( settings.value( "/Windows/SvgSelectorDialog/geometry" ).toByteArray() );
568 }
569 
571 {
572  QSettings settings;
573  settings.setValue( "/Windows/SvgSelectorDialog/geometry", saveGeometry() );
574 }
QgsSvgSelectorWidget * mSvgSelector
bool isReadable() const
void setToolTip(const QString &toolTip)
QByteArray toByteArray() const
virtual int rowCount(const QModelIndex &parent) const=0
QString currentSvgPathToName() const
iterator insert(const Key &key, const T &value)
void setupUi(QWidget *widget)
virtual void reject()
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const=0
QString path() const
void setIcon(const QIcon &icon)
QgsSvgSelectorWidget(QWidget *parent=nullptr)
static QString qgisSettingsDirPath()
Returns the path to the settings directory in user&#39;s home dir.
bool readBoolEntry(const QString &scope, const QString &key, bool def=false, bool *ok=nullptr) const
A model for displaying SVG files with a preview icon.
QStandardItem * invisibleRootItem() const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void rejected()
const T & at(int i) const
QgsSvgSelectorGroupsModel(QObject *parent)
void accepted()
QPixmap fromImage(const QImage &image, QFlags< Qt::ImageConversionFlag > flags)
void containsParams(const QString &path, bool &hasFillParam, QColor &defaultFillColor, bool &hasOutlineParam, QColor &defaultOutlineColor, bool &hasOutlineWidthParam, double &defaultOutlineWidth) const
Tests if an svg file contains parameters for fill, outline color, outline width.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
QString homePath()
QString tr(const char *sourceText, const char *disambiguation, int n)
int size() const
virtual void setData(const QVariant &value, int role)
bool isNull() const
static QgsSvgCache * instance()
Definition: qgssvgcache.cpp:97
void setValue(const QString &key, const QVariant &value)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
const QImage & svgAsImage(const QString &file, double size, const QColor &fill, const QColor &outline, double outlineWidth, double widthScaleFactor, double rasterScaleFactor, bool &fitsInCache)
Get SVG as QImage.
void setMinimumSize(const QSize &)
static QString symbolPathToName(QString path)
Get symbols&#39;s name from its path.
void addWidget(QWidget *widget, int stretch, QFlags< Qt::AlignmentFlag > alignment)
int count(const T &value) const
void append(const T &value)
QString & insert(int position, QChar ch)
void setLayout(QLayout *layout)
QModelIndex indexFromItem(const QStandardItem *item) const
QDialogButtonBox * mButtonBox
bool restoreGeometry(const QByteArray &geometry)
void svgSelected(const QString &path)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
void appendRow(const QList< QStandardItem * > &items)
virtual void select(const QModelIndex &index, QFlags< QItemSelectionModel::SelectionFlag > command)
bool isEmpty() const
QString trimmed() const
int row() const
static QString symbolNameToPath(QString name)
Get symbol&#39;s path from its name.
virtual QVariant data(const QModelIndex &index, int role) const=0
void setSvgPath(const QString &svgPath)
Accepts absolute and relative paths.
virtual void accept()
QgsSvgSelectorDialog(QWidget *parent=nullptr, const Qt::WindowFlags &fl=QgisGui::ModalDialogFlags, const QDialogButtonBox::StandardButtons &buttons=QDialogButtonBox::Close|QDialogButtonBox::Ok, Qt::Orientation orientation=Qt::Horizontal)
const T value(const Key &key) const
bool exists() const
QStandardItem * item(int row, int column) const
static QString pkgDataPath()
Returns the common root path of all application data directories.
bool contains(QChar ch, Qt::CaseSensitivity cs) const
QgsSvgSelectorListModel(QObject *parent)
Constructor for QgsSvgSelectorListModel.
void beginInsertRows(const QModelIndex &parent, int first, int last)
A model for displaying SVG search paths.
QVariant value(const QString &key, const QVariant &defaultValue) const
typedef StandardButtons
QVariant data(int role) const
void activateWindow()
QByteArray saveGeometry() const
QStyle * style()
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:382
QPixmap * find(const QString &key)
virtual int rowCount(const QModelIndex &parent) const
static QStringList svgPaths()
Returns the pathes to svg directories.
void setAlphaF(qreal alpha)
typedef WindowFlags
void setCurrentIndex(const QModelIndex &index, QFlags< QItemSelectionModel::SelectionFlag > command)
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFlags< QFileDialog::Option > options)
bool insert(const QString &key, const QPixmap &pixmap)
QString absolutePath() const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const
QString toString() const
void setCheckable(bool checkable)
void setEditable(bool editable)