Skip to content

Commit 4a594d3

Browse files
committed
[FEATURE][processing] Add buttons to save/clear/copy log
In the algorithm execution dialog, this adds buttons to allow users to save the current log (to text or HTML files), copy the log contents to the clipboard, and clear the log.
1 parent 0dfb3c2 commit 4a594d3

File tree

4 files changed

+251
-1
lines changed

4 files changed

+251
-1
lines changed

python/gui/processing/qgsprocessingalgorithmdialogbase.sip.in

+39
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ class QgsProcessingAlgorithmDialogBase : QDialog
2828
%End
2929
public:
3030

31+
enum LogFormat
32+
{
33+
FormatPlainText,
34+
FormatHtml,
35+
};
36+
3137
QgsProcessingAlgorithmDialogBase( QWidget *parent = 0, Qt::WindowFlags flags = 0 );
3238
%Docstring
3339
Constructor for QgsProcessingAlgorithmDialogBase.
@@ -93,6 +99,16 @@ slots in this dialog.
9399
virtual QVariantMap getParameterValues() const;
94100
%Docstring
95101
Returns the parameter values for the algorithm to run in the dialog.
102+
%End
103+
104+
void saveLogToFile( const QString &path, LogFormat format = FormatPlainText );
105+
%Docstring
106+
Saves the log contents to a text file (specified by the file ``path``), in
107+
the given ``format``.
108+
109+
.. versionadded:: 3.2
110+
111+
.. seealso:: :py:func:`saveLog`
96112
%End
97113

98114
public slots:
@@ -141,6 +157,29 @@ Pushes a console info string to the dialog's log.
141157
%Docstring
142158
Creates a modal progress dialog showing progress and log messages
143159
from this dialog.
160+
%End
161+
162+
void clearLog();
163+
%Docstring
164+
Clears the current log contents.
165+
166+
.. versionadded:: 3.2
167+
%End
168+
169+
void saveLog();
170+
%Docstring
171+
Opens a dialog allowing users to save the current log contents.
172+
173+
.. versionadded:: 3.2
174+
175+
.. seealso:: :py:func:`saveLogToFile`
176+
%End
177+
178+
void copyLogToClipboard();
179+
%Docstring
180+
Copies the current log contents to the clipboard.
181+
182+
.. versionadded:: 3.2
144183
%End
145184

146185
protected:

src/gui/processing/qgsprocessingalgorithmdialogbase.cpp

+72
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
#include <QToolButton>
2626
#include <QDesktopServices>
2727
#include <QScrollBar>
28+
#include <QApplication>
29+
#include <QClipboard>
30+
#include <QFileDialog>
31+
2832

2933
///@cond NOT_STABLE
3034

@@ -108,6 +112,10 @@ QgsProcessingAlgorithmDialogBase::QgsProcessingAlgorithmDialogBase( QWidget *par
108112
connect( mButtonCollapse, &QToolButton::clicked, this, &QgsProcessingAlgorithmDialogBase::toggleCollapsed );
109113
connect( splitter, &QSplitter::splitterMoved, this, &QgsProcessingAlgorithmDialogBase::splitterChanged );
110114

115+
connect( mButtonSaveLog, &QToolButton::clicked, this, &QgsProcessingAlgorithmDialogBase::saveLog );
116+
connect( mButtonCopyLog, &QToolButton::clicked, this, &QgsProcessingAlgorithmDialogBase::copyLogToClipboard );
117+
connect( mButtonClearLog, &QToolButton::clicked, this, &QgsProcessingAlgorithmDialogBase::clearLog );
118+
111119
mMessageBar = new QgsMessageBar();
112120
mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
113121
verticalLayout->insertWidget( 0, mMessageBar );
@@ -165,6 +173,27 @@ QVariantMap QgsProcessingAlgorithmDialogBase::getParameterValues() const
165173
return QVariantMap();
166174
}
167175

176+
void QgsProcessingAlgorithmDialogBase::saveLogToFile( const QString &path, const LogFormat format )
177+
{
178+
QFile logFile( path );
179+
if ( !logFile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
180+
{
181+
return;
182+
}
183+
QTextStream fout( &logFile );
184+
185+
switch ( format )
186+
{
187+
case FormatPlainText:
188+
fout << txtLog->toPlainText();
189+
break;
190+
191+
case FormatHtml:
192+
fout << txtLog->toHtml();
193+
break;
194+
}
195+
}
196+
168197
QgsProcessingFeedback *QgsProcessingAlgorithmDialogBase::createFeedback()
169198
{
170199
auto feedback = qgis::make_unique< QgsProcessingAlgorithmDialogFeedback >();
@@ -369,6 +398,49 @@ QDialog *QgsProcessingAlgorithmDialogBase::createProgressDialog()
369398
return dialog;
370399
}
371400

401+
void QgsProcessingAlgorithmDialogBase::clearLog()
402+
{
403+
txtLog->clear();
404+
}
405+
406+
void QgsProcessingAlgorithmDialogBase::saveLog()
407+
{
408+
QgsSettings settings;
409+
QString lastUsedDir = settings.value( QStringLiteral( "/Processing/lastUsedLogDirectory" ), QDir::homePath() ).toString();
410+
411+
QString filter;
412+
const QString txtExt = tr( "Text files" ) + QStringLiteral( " (*.txt *.TXT)" );
413+
const QString htmlExt = tr( "HTML files" ) + QStringLiteral( " (*.html *.HTML)" );
414+
415+
QString path = QFileDialog::getSaveFileName( this, tr( "Save Log to File" ), lastUsedDir, txtExt + ";;" + htmlExt, &filter );
416+
if ( path.isEmpty() )
417+
{
418+
return;
419+
}
420+
421+
settings.setValue( QStringLiteral( "/Processing/lastUsedLogDirectory" ), QFileInfo( path ).path() );
422+
423+
LogFormat format = FormatPlainText;
424+
if ( filter == htmlExt )
425+
{
426+
format = FormatHtml;
427+
}
428+
saveLogToFile( path, format );
429+
}
430+
431+
void QgsProcessingAlgorithmDialogBase::copyLogToClipboard()
432+
{
433+
QMimeData *m = new QMimeData();
434+
m->setText( txtLog->toPlainText() );
435+
m->setHtml( txtLog->toHtml() );
436+
QClipboard *cb = QApplication::clipboard();
437+
438+
#ifdef Q_OS_LINUX
439+
cb->setMimeData( m, QClipboard::Selection );
440+
#endif
441+
cb->setMimeData( m, QClipboard::Clipboard );
442+
}
443+
372444
void QgsProcessingAlgorithmDialogBase::closeEvent( QCloseEvent *e )
373445
{
374446
QDialog::closeEvent( e );

src/gui/processing/qgsprocessingalgorithmdialogbase.h

+37
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ class GUI_EXPORT QgsProcessingAlgorithmDialogBase : public QDialog, private Ui::
8585

8686
public:
8787

88+
/**
89+
* Log format options.
90+
* \since QGIS 3.2
91+
*/
92+
enum LogFormat
93+
{
94+
FormatPlainText, //!< Plain text file (.txt)
95+
FormatHtml, //!< HTML file (.html)
96+
};
97+
8898
/**
8999
* Constructor for QgsProcessingAlgorithmDialogBase.
90100
*/
@@ -144,6 +154,14 @@ class GUI_EXPORT QgsProcessingAlgorithmDialogBase : public QDialog, private Ui::
144154
*/
145155
virtual QVariantMap getParameterValues() const;
146156

157+
/**
158+
* Saves the log contents to a text file (specified by the file \a path), in
159+
* the given \a format.
160+
* \since QGIS 3.2
161+
* \see saveLog()
162+
*/
163+
void saveLogToFile( const QString &path, LogFormat format = FormatPlainText );
164+
147165
public slots:
148166

149167
void accept() override;
@@ -191,6 +209,25 @@ class GUI_EXPORT QgsProcessingAlgorithmDialogBase : public QDialog, private Ui::
191209
*/
192210
QDialog *createProgressDialog();
193211

212+
/**
213+
* Clears the current log contents.
214+
* \since QGIS 3.2
215+
*/
216+
void clearLog();
217+
218+
/**
219+
* Opens a dialog allowing users to save the current log contents.
220+
* \since QGIS 3.2
221+
* \see saveLogToFile()
222+
*/
223+
void saveLog();
224+
225+
/**
226+
* Copies the current log contents to the clipboard.
227+
* \since QGIS 3.2
228+
*/
229+
void copyLogToClipboard();
230+
194231
protected:
195232

196233
void closeEvent( QCloseEvent *e ) override;

src/ui/processing/qgsprocessingalgorithmdialogbase.ui

+103-1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,77 @@
8787
</property>
8888
</widget>
8989
</item>
90+
<item>
91+
<layout class="QHBoxLayout" name="horizontalLayout">
92+
<property name="bottomMargin">
93+
<number>0</number>
94+
</property>
95+
<item>
96+
<spacer name="horizontalSpacer">
97+
<property name="orientation">
98+
<enum>Qt::Horizontal</enum>
99+
</property>
100+
<property name="sizeHint" stdset="0">
101+
<size>
102+
<width>40</width>
103+
<height>20</height>
104+
</size>
105+
</property>
106+
</spacer>
107+
</item>
108+
<item>
109+
<widget class="QToolButton" name="mButtonSaveLog">
110+
<property name="toolTip">
111+
<string>Save Log to File</string>
112+
</property>
113+
<property name="text">
114+
<string>...</string>
115+
</property>
116+
<property name="icon">
117+
<iconset resource="../../../images/images.qrc">
118+
<normaloff>:/images/themes/default/mActionFileSave.svg</normaloff>:/images/themes/default/mActionFileSave.svg</iconset>
119+
</property>
120+
<property name="autoRaise">
121+
<bool>true</bool>
122+
</property>
123+
</widget>
124+
</item>
125+
<item>
126+
<widget class="QToolButton" name="mButtonCopyLog">
127+
<property name="toolTip">
128+
<string>Copy Log to Clipboard</string>
129+
</property>
130+
<property name="text">
131+
<string>...</string>
132+
</property>
133+
<property name="icon">
134+
<iconset resource="../../../images/images.qrc">
135+
<normaloff>:/images/themes/default/mActionEditCopy.svg</normaloff>:/images/themes/default/mActionEditCopy.svg</iconset>
136+
</property>
137+
<property name="autoRaise">
138+
<bool>true</bool>
139+
</property>
140+
</widget>
141+
</item>
142+
<item>
143+
<widget class="QToolButton" name="mButtonClearLog">
144+
<property name="toolTip">
145+
<string>Clear Log</string>
146+
</property>
147+
<property name="text">
148+
<string>...</string>
149+
</property>
150+
<property name="icon">
151+
<iconset resource="../../../images/images.qrc">
152+
<normaloff>:/images/themes/default/console/iconClearConsole.svg</normaloff>:/images/themes/default/console/iconClearConsole.svg</iconset>
153+
</property>
154+
<property name="autoRaise">
155+
<bool>true</bool>
156+
</property>
157+
</widget>
158+
</item>
159+
</layout>
160+
</item>
90161
</layout>
91162
</widget>
92163
</widget>
@@ -146,6 +217,37 @@
146217
</item>
147218
</layout>
148219
</widget>
149-
<resources/>
220+
<resources>
221+
<include location="../../../images/images.qrc"/>
222+
<include location="../../../images/images.qrc"/>
223+
<include location="../../../images/images.qrc"/>
224+
<include location="../../../images/images.qrc"/>
225+
<include location="../../../images/images.qrc"/>
226+
<include location="../../../images/images.qrc"/>
227+
<include location="../../../images/images.qrc"/>
228+
<include location="../../../images/images.qrc"/>
229+
<include location="../../../images/images.qrc"/>
230+
<include location="../../../images/images.qrc"/>
231+
<include location="../../../images/images.qrc"/>
232+
<include location="../../../images/images.qrc"/>
233+
<include location="../../../images/images.qrc"/>
234+
<include location="../../../images/images.qrc"/>
235+
<include location="../../../images/images.qrc"/>
236+
<include location="../../../images/images.qrc"/>
237+
<include location="../../../images/images.qrc"/>
238+
<include location="../../../images/images.qrc"/>
239+
<include location="../../../images/images.qrc"/>
240+
<include location="../../../images/images.qrc"/>
241+
<include location="../../../images/images.qrc"/>
242+
<include location="../../../images/images.qrc"/>
243+
<include location="../../../images/images.qrc"/>
244+
<include location="../../../images/images.qrc"/>
245+
<include location="../../../images/images.qrc"/>
246+
<include location="../../../images/images.qrc"/>
247+
<include location="../../../images/images.qrc"/>
248+
<include location="../../../images/images.qrc"/>
249+
<include location="../../../images/images.qrc"/>
250+
<include location="../../../images/images.qrc"/>
251+
</resources>
150252
<connections/>
151253
</ui>

0 commit comments

Comments
 (0)