13
13
* (at your option) any later version. *
15
15
***************************************************************************/
18
#include <qapplication.h>
21
#include <qsettings.h>
23
#include <q3listbox.h>
24
#include <qstringlist.h>
28
#include <qmessagebox.h>
29
#include <qinputdialog.h>
30
#include <qsettings.h>
34
#include <q3pointarray.h>
36
#include <qnamespace.h>
37
#include <q3listview.h>
38
#include <qcolordialog.h>
40
#include <qstatusbar.h>
45
#include <qtabwidget.h>
47
#include <qcheckbox.h>
48
#include <q3process.h>
51
#include <QCloseEvent>
55
#include <QHeaderView>
58
#include "qgsapplication.h"
59
#include "qgsmapcanvas.h"
60
#include "qgsmaplayer.h"
61
#include "qgsvectorlayer.h"
62
#include "qgsdataprovider.h"
64
#include "qgsfeatureattribute.h"
67
#include <grass/gis.h>
68
#include <grass/Vect.h>
71
#include "../../src/providers/grass/qgsgrass.h"
72
#include "../../src/providers/grass/qgsgrassprovider.h"
73
#include "qgsgrassattributes.h"
74
17
#include "qgsgrasstools.h"
18
#include "qgsgrassbrowser.h"
75
19
#include "qgsgrassmodule.h"
76
20
#include "qgsgrassshell.h"
77
#include "qgsgrassmodel.h"
78
#include "qgsgrassbrowser.h"
80
QgsGrassToolsTabWidget::QgsGrassToolsTabWidget( QWidget * parent ):
83
// Default height seems to be too small for our purpose
84
int height = (int)(1.5 * tabBar()->iconSize().height());
85
// Max width (see QgsGrassModule::pixmap for hardcoded sizes)
86
int width = 3*height + 28 + 29;
87
tabBar()->setIconSize( QSize(width,height) );
90
QSize QgsGrassToolsTabWidget::iconSize()
92
return tabBar()->iconSize();
95
QgsGrassToolsTabWidget::~QgsGrassToolsTabWidget() {}
97
QgsGrassTools::QgsGrassTools ( QgisApp *qgisApp, QgisIface *iface,
98
QWidget * parent, const char * name, Qt::WFlags f )
102
std::cerr << "QgsGrassTools()" << std::endl;
105
setWindowTitle ( tr("GRASS Tools") );
110
mCanvas = mIface->getMapCanvas();
112
connect( qApp, SIGNAL(aboutToQuit()),
113
this, SLOT(closeTools()) );
115
mTabWidget = new QgsGrassToolsTabWidget (this);
116
QVBoxLayout *layout1 = new QVBoxLayout(this);
117
layout1->addWidget(mTabWidget);
120
mModulesListView = new Q3ListView();
121
mTabWidget->addTab( mModulesListView, tr("Modules") );
122
mModulesListView->addColumn("col1",0);
125
mModulesListView->setColumnText(0,tr("Modules"));
126
mModulesListView->clear();
127
mModulesListView->setSorting(-1);
128
mModulesListView->setRootIsDecorated(true);
129
mModulesListView->setResizeMode(Q3ListView::AllColumns);
130
mModulesListView->header()->hide();
132
connect( mModulesListView, SIGNAL(clicked(Q3ListViewItem *)),
133
this, SLOT(moduleClicked( Q3ListViewItem *)) );
135
QString title = tr("GRASS Tools: ") + QgsGrass::getDefaultLocation()
136
+ "/" + QgsGrass::getDefaultMapset();
139
// Warning: QgsApplication initialized in main.cpp
140
// is not valid here (static libraries / linking)
142
#if defined(WIN32) || defined(Q_OS_MACX)
143
mAppDir = qApp->applicationDirPath();
148
//QString conf = QgsApplication::pkgDataPath() + "/grass/config/default.qgc";
149
QString conf = mAppDir + "/share/qgis/grass/config/default.qgc";
153
// Show before loadConfig() so that user can see loading
154
mModulesListView->show();
155
QApplication::setOverrideCursor(Qt::waitCursor);
157
QApplication::restoreOverrideCursor();
159
//statusBar()->hide();
162
// Warning: if browser is on the first page modules are
163
// displayed over the browser
164
mBrowser = new QgsGrassBrowser ( mIface, this );
165
mTabWidget->addTab( mBrowser, tr("Browser") );
167
connect( mBrowser, SIGNAL(regionChanged()),
168
this, SLOT(emitRegionChanged()) );
171
void QgsGrassTools::moduleClicked( Q3ListViewItem * item )
174
std::cerr << "QgsGrassTools::moduleClicked()" << std::endl;
178
QString name = item->text(1);
179
//std::cerr << "name = " << name << std::endl;
181
if ( name.length() == 0 ) return; // Section
183
//QString path = QgsApplication::pkgDataPath() + "/grass/modules/" + name;
184
QString path = mAppDir + "/share/qgis/grass/modules/" + name;
186
std::cerr << "path = " << path.ascii() << std::endl;
189
QgsGrassShell *sh = 0;
190
if ( name == "shell" )
193
QString mapsetPath = QgsGrass::getDefaultGisdbase() + "/"
194
+ QgsGrass::getDefaultLocation() + "/"
195
+ QgsGrass::getDefaultMapset();
198
QString hist = "HISTFILE=" + mapsetPath + "/.bash_history";
199
char *histChar = new char[hist.length()+1];
200
strcpy ( histChar, const_cast<char *>(hist.ascii()) );
23
#include "qgisinterface.h"
24
#include "qgsapplication.h"
25
#include "qgslogger.h"
27
#include <QCloseEvent>
28
#include <QDomDocument>
30
#include <QHeaderView>
31
#include <QMessageBox>
37
// For experimental model view alternative ui by Tim
40
#include "qgsdetaileditemdata.h"
41
#include "qgsdetaileditemdelegate.h"
42
#include <QSortFilterProxyModel>
43
#include <QStandardItem>
46
QgsGrassTools::QgsGrassTools( QgisInterface *iface,
47
QWidget * parent, const char * name, Qt::WFlags f )
48
: QDialog( parent, f ), QgsGrassToolsBase()
52
QgsDebugMsg( "QgsGrassTools()" );
53
qRegisterMetaType<QgsDetailedItemData>();
55
setWindowTitle( tr( "GRASS Tools" ) );
59
mCanvas = mIface->mapCanvas();
61
connect( qApp, SIGNAL( aboutToQuit() ),
62
this, SLOT( closeTools() ) );
65
// Radims original tree view code.
67
mModulesTree->header()->hide();
68
connect( mModulesTree, SIGNAL( itemClicked( QTreeWidgetItem *, int ) ),
69
this, SLOT( moduleClicked( QTreeWidgetItem *, int ) ) );
72
// Tims experimental list view with filter
74
mModelTools = new QStandardItemModel( 0, 1 );
75
mModelProxy = new QSortFilterProxyModel( this );
76
mModelProxy->setSourceModel( mModelTools );
77
mModelProxy->setFilterRole( Qt::UserRole + 2 );
79
mListView->setModel( mModelProxy );
80
mListView->setItemDelegateForColumn( 0, new QgsDetailedItemDelegate() );
81
mListView->setUniformItemSizes( false );
82
//mListView2 = new QListView(this);
83
//mDockWidget = new QDockWidget(tr("Grass Tools"), 0);
84
//mDockWidget->setWidget(mListView2);
85
//mDockWidget->setObjectName("GrassTools");
86
//mDockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
87
//mIface->addDockWidget(Qt::LeftDockWidgetArea, mDockWidget);
88
connect( mListView, SIGNAL( clicked( const QModelIndex ) ),
89
this, SLOT( listItemClicked( const QModelIndex ) ) );
91
// End of Tims experimental bit
95
// Load the modules lists
97
// Show before loadConfig() so that user can see loading
98
QString conf = QgsApplication::pkgDataPath() + "/grass/config/default.qgc";
101
QApplication::setOverrideCursor( Qt::WaitCursor );
103
QApplication::restoreOverrideCursor();
104
//statusBar()->hide();
106
// set the dialog title
107
QString title = tr( "GRASS Tools: %1/%2" ).arg( QgsGrass::getDefaultLocation() ).arg( QgsGrass::getDefaultMapset() );
108
setWindowTitle( title );
112
mBrowser = new QgsGrassBrowser( mIface, this );
113
mTabWidget->addTab( mBrowser, tr( "Browser" ) );
115
connect( mBrowser, SIGNAL( regionChanged() ),
116
this, SLOT( emitRegionChanged() ) );
119
void QgsGrassTools::moduleClicked( QTreeWidgetItem * item, int column )
121
QgsDebugMsg( "entered." );
124
QString name = item->text( 1 );
125
QgsDebugMsg( QString( "name = %1" ).arg( name ) );
129
void QgsGrassTools::runModule( QString name )
131
if ( name.length() == 0 ) return; // Section
205
hist = "histfile=" + mapsetPath + "/.history";
206
histChar = new char[hist.length()+1];
207
strcpy ( histChar, const_cast<char *>(hist.ascii()) );
134
QgsGrassShell* sh = 0;
137
QString path = QgsApplication::pkgDataPath() + "/grass/modules/" + name;
138
QgsDebugMsg( QString( "path = %1" ).arg( path ) );
140
if ( name == "shell" )
212
// Run MSYS if available
213
// Note: I was not able to run cmd.exe and command.com
216
QString msysPath = mAppDir + "/msys/bin/rxvt.exe";
217
QString myArguments = "-backspacekey ^H -sl 2500 -fg white -bg black -sr -fn Courier-16 -tn msys -geometry 80x25 -e /bin/sh --login -i";
218
QFile file ( msysPath );
220
if ( !file.exists() )
222
QMessageBox::warning( 0, tr("Warning"),
223
tr("Cannot find MSYS (") + msysPath + ")" );
227
QProcess *proc = new QProcess(this);
228
//allow msys to exist in a path with spaces
229
msysPath = "\"" + msysPath + "\"" ;
230
proc->start(msysPath + " " + myArguments);
231
proc->waitForStarted();
232
if ( proc->state() != QProcess::Running )
234
QMessageBox::warning( 0, tr("Warning"),
235
tr("Cannot start MSYS (") + msysPath + ")" );
242
sh = new QgsGrassShell(this, mTabWidget);
243
m = dynamic_cast<QWidget *> ( sh );
245
QMessageBox::warning( 0, tr("Warning"), tr("GRASS Shell is not compiled.") );
246
#endif // HAVE_OPENPTY
143
if ( !QProcess::startDetached( getenv( "COMSPEC" ) ) )
145
QMessageBox::warning( 0, "Warning", tr( "Cannot start command shell (%1)" ).arg( getenv( "COMSPEC" ) ) );
151
sh = new QgsGrassShell( this, mTabWidget );
152
m = qobject_cast<QWidget *>( sh );
154
QMessageBox::warning( 0, tr( "Warning" ), tr( "GRASS Shell is not compiled." ) );
155
#endif // HAVE_OPENPTY
248
157
#endif // ! WIN32
252
m = dynamic_cast<QWidget *> ( new QgsGrassModule ( this, name,
253
mQgisApp, mIface, path, mTabWidget ) );
256
int height = mTabWidget->iconSize().height();
257
QPixmap pixmap = QgsGrassModule::pixmap ( path, height );
259
// Icon size in QT4 does not seem to be variable
260
// -> put smaller icons in the middle
261
QPixmap pixmap2 ( mTabWidget->iconSize() );
263
pixmap2.fill ( pal.color(QPalette::Window) );
264
QPainter painter(&pixmap2);
265
int x = (int) ( (mTabWidget->iconSize().width()-pixmap.width())/2 );
266
painter.drawPixmap ( x, 0, pixmap );
270
is.addPixmap ( pixmap2 );
271
mTabWidget->addTab ( m, is, "" );
273
QgsGrassToolsTabWidget tw;
275
mTabWidget->setCurrentPage ( mTabWidget->count()-1 );
277
// We must call resize to reset COLUMNS enviroment variable
161
m = qobject_cast<QWidget *>( new QgsGrassModule( this, name,
162
mIface, path, mTabWidget ) );
165
int height = mTabWidget->iconSize().height();
166
QPixmap pixmap = QgsGrassModule::pixmap( path, height );
168
// Icon size in QT4 does not seem to be variable
169
// -> put smaller icons in the middle
170
QPixmap pixmap2( mTabWidget->iconSize() );
172
pixmap2.fill( pal.color( QPalette::Window ) );
173
QPainter painter( &pixmap2 );
174
int x = ( int )(( mTabWidget->iconSize().width() - pixmap.width() ) / 2 );
175
painter.drawPixmap( x, 0, pixmap );
179
is.addPixmap( pixmap2 );
180
mTabWidget->addTab( m, is, "" );
183
mTabWidget->setCurrentIndex( mTabWidget->count() - 1 );
185
// We must call resize to reset COLUMNS environment variable
188
/* TODO: Implement something that resizes the terminal without
280
191
if ( sh ) sh->resizeTerminal();
284
bool QgsGrassTools::loadConfig(QString filePath)
287
std::cerr << "QgsGrassTools::loadConfig(): " << filePath.toLocal8Bit().data() << std::endl;
289
mModulesListView->clear();
291
QFile file ( filePath );
293
if ( !file.exists() ) {
294
QMessageBox::warning( 0, tr("Warning"), tr("The config file (") + filePath + tr(") not found.") );
297
if ( ! file.open( QIODevice::ReadOnly ) ) {
298
QMessageBox::warning( 0, tr("Warning"), tr("Cannot open config file (") + filePath + tr(")") );
302
QDomDocument doc ( "qgisgrass" );
305
if ( !doc.setContent( &file, &err, &line, &column ) ) {
306
QString errmsg = tr("Cannot read config file (") + filePath + "):\n" + err + tr("\nat line ")
307
+ QString::number(line) + tr(" column ") + QString::number(column);
308
std::cerr << errmsg.toLocal8Bit().data() << std::endl;
309
QMessageBox::warning( 0, tr("Warning"), errmsg );
314
QDomElement docElem = doc.documentElement();
315
QDomNodeList modulesNodes = docElem.elementsByTagName ( "modules" );
317
if ( modulesNodes.count() == 0 ) {
322
QDomNode modulesNode = modulesNodes.item(0);
323
QDomElement modulesElem = modulesNode.toElement();
325
// Go through the sections and modules and add them to the list view
326
addModules ( 0, modulesElem );
331
void QgsGrassTools::addModules ( Q3ListViewItem *parent, QDomElement &element )
333
QDomNode n = element.firstChild();
335
Q3ListViewItem *item;
336
Q3ListViewItem *lastItem = 0;
337
while( !n.isNull() ) {
338
QDomElement e = n.toElement();
340
//std::cout << "tag = " << e.tagName() << std::endl;
342
if ( e.tagName() == "section" && e.tagName() == "grass" ) {
343
std::cout << "Unknown tag: " << e.tagName().toLocal8Bit().data() << std::endl;
348
item = new Q3ListViewItem( parent, lastItem );
350
item = new Q3ListViewItem( mModulesListView, lastItem );
353
if ( e.tagName() == "section" ) {
354
QString label = e.attribute("label");
355
std::cout << "label = " << label.toLocal8Bit().data() << std::endl;
356
item->setText( 0, label );
357
item->setOpen(true); // for debuging to spare one click
359
addModules ( item, e );
362
} else if ( e.tagName() == "grass" ) { // GRASS module
363
QString name = e.attribute("name");
364
std::cout << "name = " << name.toLocal8Bit().data() << std::endl;
366
//QString path = QgsApplication::pkgDataPath() + "/grass/modules/" + name;
367
QString path = mAppDir + "/share/qgis/grass/modules/" + name;
368
QString label = QgsGrassModule::label ( path );
369
QPixmap pixmap = QgsGrassModule::pixmap ( path, 25 );
371
item->setText( 0, label );
372
item->setPixmap( 0, pixmap );
373
item->setText( 1, name );
376
// Show items during loading
377
mModulesListView->repaint();
196
bool QgsGrassTools::loadConfig( QString filePath )
198
QgsDebugMsg( filePath );
199
mModulesTree->clear();
200
mModulesTree->setIconSize( QSize( 80, 22 ) );
202
QFile file( filePath );
204
if ( !file.exists() )
206
QMessageBox::warning( 0, tr( "Warning" ), tr( "The config file (%1) not found." ).arg( filePath ) );
209
if ( ! file.open( QIODevice::ReadOnly ) )
211
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot open config file (%1)." ).arg( filePath ) );
215
QDomDocument doc( "qgisgrass" );
218
if ( !doc.setContent( &file, &err, &line, &column ) )
220
QString errmsg = tr( "Cannot read config file (%1):" ).arg( filePath )
221
+ tr( "\n%1\nat line %2 column %3" ).arg( err ).arg( line ).arg( column );
222
QgsDebugMsg( errmsg );
223
QMessageBox::warning( 0, tr( "Warning" ), errmsg );
228
QDomElement docElem = doc.documentElement();
229
QDomNodeList modulesNodes = docElem.elementsByTagName( "modules" );
231
if ( modulesNodes.count() == 0 )
237
QDomNode modulesNode = modulesNodes.item( 0 );
238
QDomElement modulesElem = modulesNode.toElement();
240
// Go through the sections and modules and add them to the list view
241
addModules( 0, modulesElem );
243
mModulesTree->topLevelItem( 0 )->setExpanded( true );
249
void QgsGrassTools::addModules( QTreeWidgetItem *parent, QDomElement &element )
251
QDomNode n = element.firstChild();
253
QTreeWidgetItem *item;
254
QTreeWidgetItem *lastItem = 0;
255
while ( !n.isNull() )
257
QDomElement e = n.toElement();
260
// QgsDebugMsg(QString("tag = %1").arg(e.tagName()));
262
if ( e.tagName() == "section" && e.tagName() == "grass" )
264
QgsDebugMsg( QString( "Unknown tag: %1" ).arg( e.tagName() ) );
270
item = new QTreeWidgetItem( parent, lastItem );
274
item = new QTreeWidgetItem( mModulesTree, lastItem );
277
if ( e.tagName() == "section" )
279
QString label = e.attribute( "label" );
280
QgsDebugMsg( QString( "label = %1" ).arg( label ) );
281
item->setText( 0, label );
282
item->setExpanded( false );
284
addModules( item, e );
288
else if ( e.tagName() == "grass" )
290
QString name = e.attribute( "name" );
291
QgsDebugMsg( QString( "name = %1" ).arg( name ) );
293
QString path = QgsApplication::pkgDataPath() + "/grass/modules/" + name;
294
QString label = QgsGrassModule::label( path );
295
QPixmap pixmap = QgsGrassModule::pixmap( path, 25 );
297
item->setText( 0, name + " - " + label );
298
item->setIcon( 0, QIcon( pixmap ) );
299
item->setText( 1, name );
304
// Experimental work by Tim - add this item to our list model
306
QStandardItem * mypDetailItem = new QStandardItem( name );
307
mypDetailItem->setData( name, Qt::UserRole + 1 ); //for calling runModule later
308
QString mySearchText = name + " - " + label;
309
mypDetailItem->setData( mySearchText, Qt::UserRole + 2 ); //for filtering later
310
mypDetailItem->setData( pixmap, Qt::DecorationRole );
311
mypDetailItem->setCheckable( false );
312
mypDetailItem->setEditable( false );
313
// setData in the delegate with a variantised QgsDetailedItemData
314
QgsDetailedItemData myData;
315
myData.setTitle( name );
316
myData.setDetail( label );
317
myData.setIcon( pixmap );
318
myData.setCheckable( false );
319
myData.setRenderAsWidget( true );
320
QVariant myVariant = qVariantFromValue( myData );
321
mypDetailItem->setData( myVariant, Qt::UserRole );
322
mModelTools->appendRow( mypDetailItem );
324
// End of experimental work by Tim
383
332
void QgsGrassTools::mapsetChanged()
386
std::cerr << "QgsGrassTools::mapsetChanged()" << std::endl;
389
QString title = tr("GRASS Tools: ") + QgsGrass::getDefaultLocation()
390
+ "/" + QgsGrass::getDefaultMapset();
394
mBrowser->setLocation( QgsGrass::getDefaultGisdbase(), QgsGrass::getDefaultLocation() );
334
QgsDebugMsg( "entered." );
336
QString title = tr( "GRASS Tools: %1/%2" ).arg( QgsGrass::getDefaultLocation() ).arg( QgsGrass::getDefaultMapset() );
337
setWindowTitle( title );
340
mBrowser->setLocation( QgsGrass::getDefaultGisdbase(), QgsGrass::getDefaultLocation() );
397
343
QgsGrassTools::~QgsGrassTools()
400
std::cerr << "QgsGrassTools::~QgsGrassTools()" << std::endl;
402
saveWindowLocation();
405
QString QgsGrassTools::appDir(void)
407
//return QgsApplication::applicationDirPath();
411
void QgsGrassTools::close(void)
413
saveWindowLocation();
417
void QgsGrassTools::closeEvent(QCloseEvent *e)
419
saveWindowLocation();
345
QgsDebugMsg( "entered." );
346
saveWindowLocation();
349
QString QgsGrassTools::appDir( void )
352
return QgsGrass::shortPath( QgsApplication::applicationDirPath() );
354
return QgsApplication::applicationDirPath();
358
void QgsGrassTools::close( void )
360
saveWindowLocation();
364
void QgsGrassTools::closeEvent( QCloseEvent *e )
366
saveWindowLocation();
423
370
void QgsGrassTools::restorePosition()
426
int ww = settings.readNumEntry("/GRASS/windows/tools/w", 250);
427
int wh = settings.readNumEntry("/GRASS/windows/tools/h", 300);
428
int wx = settings.readNumEntry("/GRASS/windows/tools/x", 100);
429
int wy = settings.readNumEntry("/GRASS/windows/tools/y", 100);
373
restoreGeometry( settings.value( "/GRASS/windows/tools/geometry" ).toByteArray() );
435
377
void QgsGrassTools::saveWindowLocation()
438
QPoint p = this->pos();
439
QSize s = this->size();
440
settings.writeEntry("/GRASS/windows/tools/x", p.x());
441
settings.writeEntry("/GRASS/windows/tools/y", p.y());
442
settings.writeEntry("/GRASS/windows/tools/w", s.width());
443
settings.writeEntry("/GRASS/windows/tools/h", s.height());
380
settings.setValue( "/GRASS/windows/tools/geometry", saveGeometry() );
446
383
void QgsGrassTools::emitRegionChanged()
449
std::cerr << "QgsGrassTools::emitRegionChanged()" << std::endl;
451
emit regionChanged();
385
QgsDebugMsg( "entered." );
386
emit regionChanged();
454
389
void QgsGrassTools::closeTools()
457
std::cerr << "QgsGrassTools::closeTools()" << std::endl;
460
for ( int i = mTabWidget->count()-1; i > 1; i-- )
462
delete mTabWidget->widget(i);
463
mTabWidget->removeTab(i);
391
QgsDebugMsg( "entered." );
393
for ( int i = mTabWidget->count() - 1; i > 2; i-- )
395
delete mTabWidget->widget( i );
396
mTabWidget->removeTab( i );
403
// Helper function for Tim's experimental model list
406
void QgsGrassTools::on_mFilterInput_textChanged( QString theText )
408
QgsDebugMsg( "GRASS modules filter changed to :" + theText );
409
QRegExp::PatternSyntax mySyntax = QRegExp::PatternSyntax( QRegExp::RegExp );
410
Qt::CaseSensitivity myCaseSensitivity = Qt::CaseInsensitive;
411
QRegExp myRegExp( theText, myCaseSensitivity, mySyntax );
412
mModelProxy->setFilterRegExp( myRegExp );
415
void QgsGrassTools::listItemClicked( const QModelIndex &theIndex )
417
if ( theIndex.column() == 0 )
420
// If the model has been filtered, the index row in the proxy wont match
421
// the index row in the underlying model so we need to jump through this
422
// little hoop to get the correct item
424
QStandardItem * mypItem =
425
mModelTools->findItems( theIndex.data( Qt::DisplayRole ).toString() ).first();
426
QString myModuleName = mypItem->data( Qt::UserRole + 1 ).toString();
427
runModule( myModuleName );