QGIS API Documentation  3.6.0-Noosa (5873452)
qgsguiutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsguiutils.cpp - Constants used throughout the QGIS GUI.
3  --------------------------------------
4  Date : 11-Jan-2006
5  Copyright : (C) 2006 by Tom Elwertowski
6  Email : telwertowski at users dot sourceforge dot net
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 #include "qgsguiutils.h"
16 
17 #include "qgssettings.h"
18 #include "qgsencodingfiledialog.h"
19 #include "qgslogger.h"
20 #include "qgis_gui.h"
21 #include "qgis.h"
22 
23 #include <QImageWriter>
24 #include <QFontDialog>
25 #include <QApplication>
26 
27 
28 namespace QgsGuiUtils
29 {
30 
31  bool GUI_EXPORT openFilesRememberingFilter( QString const &filterName,
32  QString const &filters, QStringList &selectedFiles, QString &enc, QString &title,
33  bool cancelAll )
34  {
35  Q_UNUSED( enc );
36 
37  QgsSettings settings;
38  QString lastUsedFilter = settings.value( "/UI/" + filterName, "" ).toString();
39  QString lastUsedDir = settings.value( "/UI/" + filterName + "Dir", QDir::homePath() ).toString();
40 
41  QgsDebugMsg( "Opening file dialog with filters: " + filters );
42  if ( !cancelAll )
43  {
44  selectedFiles = QFileDialog::getOpenFileNames( nullptr, title, lastUsedDir, filters, &lastUsedFilter );
45  }
46  else //we have to use non-native dialog to add cancel all button
47  {
48  QgsEncodingFileDialog *openFileDialog = new QgsEncodingFileDialog( nullptr, title, lastUsedDir, filters, QString() );
49 
50  // allow for selection of more than one file
51  openFileDialog->setFileMode( QFileDialog::ExistingFiles );
52 
53  if ( !lastUsedFilter.isEmpty() )
54  {
55  openFileDialog->selectNameFilter( lastUsedFilter );
56  }
57  openFileDialog->addCancelAll();
58  if ( openFileDialog->exec() == QDialog::Accepted )
59  {
60  selectedFiles = openFileDialog->selectedFiles();
61  }
62  else
63  {
64  //cancel or cancel all?
65  if ( openFileDialog->cancelAll() )
66  {
67  return true;
68  }
69  }
70  }
71 
72  if ( !selectedFiles.isEmpty() )
73  {
74  // Fix by Tim - getting the dirPath from the dialog
75  // directly truncates the last node in the dir path.
76  // This is a workaround for that
77  QString firstFileName = selectedFiles.first();
78  QFileInfo fi( firstFileName );
79  QString path = fi.path();
80 
81  QgsDebugMsg( "Writing last used dir: " + path );
82 
83  settings.setValue( "/UI/" + filterName, lastUsedFilter );
84  settings.setValue( "/UI/" + filterName + "Dir", path );
85  }
86  return false;
87  }
88 
89  QPair<QString, QString> GUI_EXPORT getSaveAsImageName( QWidget *parent, const QString &message, const QString &defaultFilename )
90  {
91  // get a list of supported output image types
92  QMap<QString, QString> filterMap;
93  Q_FOREACH ( const QByteArray &format, QImageWriter::supportedImageFormats() )
94  {
95  //svg doesn't work so skip it
96  if ( format == "svg" )
97  continue;
98 
99  filterMap.insert( createFileFilter_( format ), format );
100  }
101 
102 #ifdef QGISDEBUG
103  QgsDebugMsg( QStringLiteral( "Available Filters Map: " ) );
104  for ( QMap<QString, QString>::iterator it = filterMap.begin(); it != filterMap.end(); ++it )
105  {
106  QgsDebugMsg( it.key() + " : " + it.value() );
107  }
108 #endif
109 
110  QgsSettings settings; // where we keep last used filter in persistent state
111  QString lastUsedDir = settings.value( QStringLiteral( "UI/lastSaveAsImageDir" ), QDir::homePath() ).toString();
112 
113  // Prefer "png" format unless the user previously chose a different format
114  QString pngExtension = QStringLiteral( "png" );
115  QString pngFilter = createFileFilter_( pngExtension );
116  QString selectedFilter = settings.value( QStringLiteral( "UI/lastSaveAsImageFilter" ), pngFilter ).toString();
117 
118  QString initialPath;
119  if ( defaultFilename.isNull() )
120  {
121  //no default filename provided, just use last directory
122  initialPath = lastUsedDir;
123  }
124  else
125  {
126  //a default filename was provided, so use it to build the initial path
127  initialPath = QDir( lastUsedDir ).filePath( defaultFilename );
128  }
129 
130  QString outputFileName;
131  QString ext;
132 #if defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(Q_OS_LINUX)
133  outputFileName = QFileDialog::getSaveFileName( parent, message, initialPath, QStringList( filterMap.keys() ).join( QStringLiteral( ";;" ) ), &selectedFilter );
134 
135  if ( !outputFileName.isNull() )
136  {
137  ext = filterMap.value( selectedFilter, QString() );
138  if ( !ext.isNull() )
139  settings.setValue( QStringLiteral( "UI/lastSaveAsImageFilter" ), selectedFilter );
140  settings.setValue( QStringLiteral( "UI/lastSaveAsImageDir" ), QFileInfo( outputFileName ).absolutePath() );
141  }
142 #else
143 
144  //create a file dialog using the filter list generated above
145  std::unique_ptr<QFileDialog> fileDialog( new QFileDialog( parent, message, initialPath, QStringList( filterMap.keys() ).join( ";;" ) ) );
146 
147  // allow for selection of more than one file
148  fileDialog->setFileMode( QFileDialog::AnyFile );
149  fileDialog->setAcceptMode( QFileDialog::AcceptSave );
150  fileDialog->setOption( QFileDialog::DontConfirmOverwrite, false );
151 
152  if ( !selectedFilter.isEmpty() ) // set the filter to the last one used
153  {
154  fileDialog->selectNameFilter( selectedFilter );
155  }
156 
157  //prompt the user for a fileName
158  if ( fileDialog->exec() == QDialog::Accepted )
159  {
160  outputFileName = fileDialog->selectedFiles().first();
161  }
162 
163  selectedFilter = fileDialog->selectedNameFilter();
164  QgsDebugMsg( "Selected filter: " + selectedFilter );
165  ext = filterMap.value( selectedFilter, QString() );
166 
167  if ( !ext.isNull() )
168  settings.setValue( "/UI/lastSaveAsImageFilter", selectedFilter );
169 
170  settings.setValue( "/UI/lastSaveAsImageDir", fileDialog->directory().absolutePath() );
171 #endif
172 
173  // Add the file type suffix to the fileName if required
174  if ( !ext.isNull() && !outputFileName.endsWith( '.' + ext.toLower(), Qt::CaseInsensitive ) )
175  {
176  outputFileName += '.' + ext;
177  }
178 
179  return qMakePair<QString, QString>( outputFileName, ext );
180  }
181 
182  QString createFileFilter_( QString const &longName, QString const &glob )
183  {
184  return QStringLiteral( "%1 (%2 %3)" ).arg( longName, glob.toLower(), glob.toUpper() );
185  }
186 
187  QString createFileFilter_( QString const &format )
188  {
189  QString longName = format.toUpper() + " format";
190  QString glob = "*." + format;
191  return createFileFilter_( longName, glob );
192  }
193 
194  QFont getFont( bool &ok, const QFont &initial, const QString &title )
195  {
196  // parent is intentionally not set to 'this' as
197  // that would make it follow the style sheet font
198  // see also #12233 and #4937
199 #if defined(Q_OS_MAC)
200  // Native dialog broken on macOS with Qt5
201  // probably only broken in Qt5.11.1 and .2
202  // (see https://successfulsoftware.net/2018/11/02/qt-is-broken-on-macos-right-now/ )
203  // possible upstream bug: https://bugreports.qt.io/browse/QTBUG-69878 (fixed in Qt 5.12 ?)
204  return QFontDialog::getFont( &ok, initial, nullptr, title, QFontDialog::DontUseNativeDialog );
205 #else
206  return QFontDialog::getFont( &ok, initial, nullptr, title );
207 #endif
208  }
209 
210  void saveGeometry( QWidget *widget, const QString &keyName )
211  {
212  QgsSettings settings;
213  QString key = createWidgetKey( widget, keyName );
214  settings.setValue( key, widget->saveGeometry() );
215  }
216 
217  bool restoreGeometry( QWidget *widget, const QString &keyName )
218  {
219  QgsSettings settings;
220  QString key = createWidgetKey( widget, keyName );
221  return widget->restoreGeometry( settings.value( key ).toByteArray() );
222  }
223 
224  QString createWidgetKey( QWidget *widget, const QString &keyName )
225  {
226  QString subKey;
227  if ( !keyName.isEmpty() )
228  {
229  subKey = keyName;
230  }
231  else if ( widget->objectName().isEmpty() )
232  {
233  subKey = QString( widget->metaObject()->className() );
234  }
235  else
236  {
237  subKey = widget->objectName();
238  }
239  QString key = QStringLiteral( "Windows/%1/geometry" ).arg( subKey );
240  return key;
241  }
242 
243  int scaleIconSize( int standardSize )
244  {
245  QFontMetrics fm( ( QFont() ) );
246  const double scale = 1.1 * standardSize / 24;
247  return static_cast< int >( std::floor( std::max( Qgis::UI_SCALE_FACTOR * fm.height() * scale, static_cast< double >( standardSize ) ) ) );
248  }
249 
250 }
251 
252 //
253 // QgsTemporaryCursorOverride
254 //
255 
257 {
258  QApplication::setOverrideCursor( cursor );
259 }
260 
262 {
263  if ( mHasOverride )
264  QApplication::restoreOverrideCursor();
265 }
266 
268 {
269  if ( !mHasOverride )
270  return;
271 
272  mHasOverride = false;
273  QApplication::restoreOverrideCursor();
274 }
A file dialog which lets the user select the preferred encoding type for a data provider.
QString createFileFilter_(QString const &longName, QString const &glob)
Convenience function for readily creating file filters.
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:139
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly...
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QPair< QString, QString > GUI_EXPORT getSaveAsImageName(QWidget *parent, const QString &message, const QString &defaultFilename)
A helper function to get an image name from the user.
Definition: qgsguiutils.cpp:89
void saveGeometry(QWidget *widget, const QString &keyName)
Save the wigget geometry into settings.
bool restoreGeometry(QWidget *widget, const QString &keyName)
Restore the wigget geometry from settings.
The QgsGuiUtils namespace contains constants and helper functions used throughout the QGIS GUI...
Definition: qgsguiutils.cpp:28
void addCancelAll()
Adds a &#39;Cancel All&#39; button for the user to click.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
void release()
Releases the cursor override early (i.e.
bool cancelAll()
Returns true if the user clicked &#39;Cancel All&#39;.
QString createWidgetKey(QWidget *widget, const QString &keyName)
Creates a key for the given widget that can be used to store related data in settings.
QgsTemporaryCursorOverride(const QCursor &cursor)
Constructor for QgsTemporaryCursorOverride.
bool GUI_EXPORT openFilesRememberingFilter(QString const &filterName, QString const &filters, QStringList &selectedFiles, QString &enc, QString &title, bool cancelAll)
Open files, preferring to have the default file selector be the last one used, if any; also...
Definition: qgsguiutils.cpp:31
QFont getFont(bool &ok, const QFont &initial, const QString &title)
Show font selection dialog.