qgsbrowserdockwidget.cpp

my workaround. line 294-302 - Hanif Rifai, 2017-10-22 02:56 PM

Download (17.7 KB)

 
1
/***************************************************************************
2
    qgsbrowserdockwidget.cpp
3
    ---------------------
4
    begin                : July 2011
5
    copyright            : (C) 2011 by Martin Dobias
6
    email                : wonder dot sk at gmail dot com
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 "qgsbrowserdockwidget.h"
16
#include "qgsbrowserdockwidget_p.h"
17

    
18
#include <QAbstractTextDocumentLayout>
19
#include <QHeaderView>
20
#include <QTreeView>
21
#include <QMenu>
22
#include <QToolButton>
23
#include <QFileDialog>
24
#include <QPlainTextDocumentLayout>
25
#include <QSortFilterProxyModel>
26

    
27
#include "qgsbrowsermodel.h"
28
#include "qgsbrowsertreeview.h"
29
#include "qgslogger.h"
30
#include "qgsrasterlayer.h"
31
#include "qgsvectorlayer.h"
32
#include "qgsproject.h"
33
#include "qgssettings.h"
34

    
35
// browser layer properties dialog
36
#include "qgsapplication.h"
37
#include "qgsmapcanvas.h"
38

    
39
#include <QDragEnterEvent>
40

    
41
QgsBrowserDockWidget::QgsBrowserDockWidget( const QString &name, QgsBrowserModel *browserModel, QWidget *parent )
42
  : QgsDockWidget( parent )
43
  , mModel( browserModel )
44
  , mPropertiesWidgetEnabled( false )
45
  , mPropertiesWidgetHeight( 0 )
46
{
47
  setupUi( this );
48

    
49
  mContents->layout()->setContentsMargins( 0, 0, 0, 0 );
50
  mContents->layout()->setMargin( 0 );
51
  static_cast< QVBoxLayout * >( mContents->layout() )->setSpacing( 0 );
52

    
53
  setWindowTitle( name );
54

    
55
  mBrowserView = new QgsDockBrowserTreeView( this );
56
  mLayoutBrowser->addWidget( mBrowserView );
57

    
58
  mWidgetFilter->hide();
59
  mLeFilter->setPlaceholderText( tr( "Type here to filter visible items..." ) );
60
  // icons from http://www.fatcow.com/free-icons License: CC Attribution 3.0
61

    
62
  QMenu *menu = new QMenu( this );
63
  menu->setSeparatorsCollapsible( false );
64
  mBtnFilterOptions->setMenu( menu );
65
  QAction *action = new QAction( tr( "Case Sensitive" ), menu );
66
  action->setData( "case" );
67
  action->setCheckable( true );
68
  action->setChecked( false );
69
  connect( action, &QAction::toggled, this, &QgsBrowserDockWidget::setCaseSensitive );
70
  menu->addAction( action );
71
  QActionGroup *group = new QActionGroup( menu );
72
  action = new QAction( tr( "Filter Pattern Syntax" ), group );
73
  action->setSeparator( true );
74
  menu->addAction( action );
75
  action = new QAction( tr( "Normal" ), group );
76
  action->setData( "normal" );
77
  action->setCheckable( true );
78
  action->setChecked( true );
79
  menu->addAction( action );
80
  action = new QAction( tr( "Wildcard(s)" ), group );
81
  action->setData( "wildcard" );
82
  action->setCheckable( true );
83
  menu->addAction( action );
84
  action = new QAction( tr( "Regular Expression" ), group );
85
  action->setData( "regexp" );
86
  action->setCheckable( true );
87
  menu->addAction( action );
88

    
89
  connect( mActionRefresh, &QAction::triggered, this, &QgsBrowserDockWidget::refresh );
90
  connect( mActionAddLayers, &QAction::triggered, this, &QgsBrowserDockWidget::addSelectedLayers );
91
  connect( mActionCollapse, &QAction::triggered, mBrowserView, &QgsDockBrowserTreeView::collapseAll );
92
  connect( mActionShowFilter, &QAction::triggered, this, &QgsBrowserDockWidget::showFilterWidget );
93
  connect( mActionPropertiesWidget, &QAction::triggered, this, &QgsBrowserDockWidget::enablePropertiesWidget );
94
  connect( mLeFilter, &QgsFilterLineEdit::returnPressed, this, &QgsBrowserDockWidget::setFilter );
95
  connect( mLeFilter, &QgsFilterLineEdit::cleared, this, &QgsBrowserDockWidget::setFilter );
96
  connect( mLeFilter, &QgsFilterLineEdit::textChanged, this, &QgsBrowserDockWidget::setFilter );
97
  connect( group, &QActionGroup::triggered, this, &QgsBrowserDockWidget::setFilterSyntax );
98
  connect( mBrowserView, &QgsDockBrowserTreeView::customContextMenuRequested, this, &QgsBrowserDockWidget::showContextMenu );
99
  connect( mBrowserView, &QgsDockBrowserTreeView::doubleClicked, this, &QgsBrowserDockWidget::itemDoubleClicked );
100
  connect( mSplitter, &QSplitter::splitterMoved, this, &QgsBrowserDockWidget::splitterMoved );
101
}
102

    
103
QgsBrowserDockWidget::~QgsBrowserDockWidget()
104
{
105
  QgsSettings settings;
106
  settings.setValue( settingsSection() + "/propertiesWidgetEnabled", mPropertiesWidgetEnabled );
107
  //settings.setValue(settingsSection() + "/propertiesWidgetHeight", mPropertiesWidget->size().height() );
108
  settings.setValue( settingsSection() + "/propertiesWidgetHeight", mPropertiesWidgetHeight );
109
}
110

    
111
void QgsBrowserDockWidget::showEvent( QShowEvent *e )
112
{
113
  // delayed initialization of the model
114
  if ( !mModel->initialized( ) )
115
  {
116
    mModel->initialize();
117
  }
118
  if ( mProxyModel == nullptr )
119
  {
120
    mProxyModel = new QgsBrowserTreeFilterProxyModel( this );
121
    mProxyModel->setBrowserModel( mModel );
122
    mBrowserView->setSettingsSection( objectName().toLower() ); // to distinguish 2 or more instances of the browser
123
    mBrowserView->setBrowserModel( mModel );
124
    mBrowserView->setModel( mProxyModel );
125
    // provide a horizontal scroll bar instead of using ellipse (...) for longer items
126
    mBrowserView->setTextElideMode( Qt::ElideNone );
127
    mBrowserView->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
128
    mBrowserView->header()->setStretchLastSection( false );
129

    
130
    // selectionModel is created when model is set on tree
131
    connect( mBrowserView->selectionModel(), &QItemSelectionModel::selectionChanged,
132
             this, &QgsBrowserDockWidget::selectionChanged );
133

    
134
    // Forward the model changed signals to the widget
135
    connect( mModel, &QgsBrowserModel::connectionsChanged,
136
             this, &QgsBrowserDockWidget::connectionsChanged );
137

    
138

    
139
    // objectName used by settingsSection() is not yet set in constructor
140
    QgsSettings settings;
141
    mPropertiesWidgetEnabled = settings.value( settingsSection() + "/propertiesWidgetEnabled", false ).toBool();
142
    mActionPropertiesWidget->setChecked( mPropertiesWidgetEnabled );
143
    mPropertiesWidget->setVisible( false ); // false until item is selected
144

    
145
    mPropertiesWidgetHeight = settings.value( settingsSection() + "/propertiesWidgetHeight" ).toFloat();
146
    QList<int> sizes = mSplitter->sizes();
147
    int total = sizes.value( 0 ) + sizes.value( 1 );
148
    int height = ( int )total * mPropertiesWidgetHeight;
149
    sizes.clear();
150
    sizes << total - height << height;
151
    mSplitter->setSizes( sizes );
152
  }
153

    
154
  QgsDockWidget::showEvent( e );
155
}
156

    
157
void QgsBrowserDockWidget::itemDoubleClicked( const QModelIndex &index )
158
{
159
  QgsDataItem *item = mModel->dataItem( mProxyModel->mapToSource( index ) );
160
  if ( !item )
161
    return;
162

    
163
  if ( item->handleDoubleClick() )
164
    return;
165
  else
166
    addLayerAtIndex( index ); // default double-click handler
167
}
168

    
169
void QgsBrowserDockWidget::showContextMenu( QPoint pt )
170
{
171
  QModelIndex index = mProxyModel->mapToSource( mBrowserView->indexAt( pt ) );
172
  QgsDataItem *item = mModel->dataItem( index );
173
  if ( !item )
174
    return;
175

    
176
  QMenu *menu = new QMenu( this );
177

    
178
  if ( item->type() == QgsDataItem::Directory )
179
  {
180
    QgsSettings settings;
181
    QStringList favDirs = settings.value( QStringLiteral( "browser/favourites" ) ).toStringList();
182
    bool inFavDirs = item->parent() && item->parent()->type() == QgsDataItem::Favorites;
183

    
184
    if ( item->parent() && !inFavDirs )
185
    {
186
      // only non-root directories can be added as favorites
187
      menu->addAction( tr( "Add as a Favorite" ), this, SLOT( addFavorite() ) );
188
    }
189
    else if ( inFavDirs )
190
    {
191
      // only favorites can be removed
192
      menu->addAction( tr( "Remove Favorite" ), this, SLOT( removeFavorite() ) );
193
    }
194
    menu->addAction( tr( "Properties..." ), this, SLOT( showProperties() ) );
195
    menu->addAction( tr( "Hide from Browser" ), this, SLOT( hideItem() ) );
196
    QAction *action = menu->addAction( tr( "Fast Scan this Directory" ), this, SLOT( toggleFastScan() ) );
197
    action->setCheckable( true );
198
    action->setChecked( settings.value( QStringLiteral( "qgis/scanItemsFastScanUris" ),
199
                                        QStringList() ).toStringList().contains( item->path() ) );
200
  }
201
  else if ( item->type() == QgsDataItem::Layer )
202
  {
203
    menu->addAction( tr( "Add Selected Layer(s) to Canvas" ), this, SLOT( addSelectedLayers() ) );
204
    menu->addAction( tr( "Properties..." ), this, SLOT( showProperties() ) );
205
  }
206
  else if ( item->type() == QgsDataItem::Favorites )
207
  {
208
    menu->addAction( tr( "Add a Directory..." ), this, SLOT( addFavoriteDirectory() ) );
209
  }
210

    
211
  const QList<QMenu *> menus = item->menus( menu );
212
  QList<QAction *> actions = item->actions( menu );
213

    
214
  if ( !menus.isEmpty() )
215
  {
216
    for ( QMenu *mn : menus )
217
    {
218
      menu->addMenu( mn );
219
    }
220
  }
221

    
222
  if ( !actions.isEmpty() )
223
  {
224
    if ( !menu->actions().isEmpty() )
225
      menu->addSeparator();
226
    // add action to the menu
227
    menu->addActions( actions );
228
  }
229

    
230
  if ( menu->actions().isEmpty() )
231
  {
232
    delete menu;
233
    return;
234
  }
235

    
236
  menu->popup( mBrowserView->mapToGlobal( pt ) );
237
}
238

    
239
void QgsBrowserDockWidget::addFavorite()
240
{
241
  QModelIndex index = mProxyModel->mapToSource( mBrowserView->currentIndex() );
242
  QgsDataItem *item = mModel->dataItem( index );
243
  if ( !item )
244
    return;
245

    
246
  QgsDirectoryItem *dirItem = dynamic_cast<QgsDirectoryItem *>( item );
247
  if ( !dirItem )
248
    return;
249

    
250
  addFavoriteDirectory( dirItem->dirPath() );
251
}
252

    
253
void QgsBrowserDockWidget::addFavoriteDirectory()
254
{
255
  QString directory = QFileDialog::getExistingDirectory( this, tr( "Add directory to favorites" ) );
256
  if ( !directory.isEmpty() )
257
  {
258
    addFavoriteDirectory( directory );
259
  }
260
}
261

    
262
void QgsBrowserDockWidget::addFavoriteDirectory( const QString &favDir )
263
{
264
  mModel->addFavoriteDirectory( favDir );
265
}
266

    
267
void QgsBrowserDockWidget::removeFavorite()
268
{
269
  mModel->removeFavorite( mProxyModel->mapToSource( mBrowserView->currentIndex() ) );
270
}
271

    
272
void QgsBrowserDockWidget::refresh()
273
{
274
  if ( mModel )
275
    refreshModel( QModelIndex() );
276
}
277

    
278
void QgsBrowserDockWidget::refreshModel( const QModelIndex &index )
279
{
280
  QgsDataItem *item = mModel->dataItem( index );
281
  if ( item )
282
  {
283
    QgsDebugMsg( "path = " + item->path() );
284
  }
285
  else
286
  {
287
    QgsDebugMsg( "invalid item" );
288
  }
289

    
290
  if ( item && ( item->capabilities2() & QgsDataItem::Fertile ) )
291
  {
292
    mModel->refresh( index );
293
  }
294

    
295
  if (mProxyModel == nullptr)
296
  {
297
          mProxyModel = new QgsBrowserTreeFilterProxyModel(this);
298
          mProxyModel->setBrowserModel(mModel);
299
          mBrowserView->setSettingsSection(objectName().toLower()); // to distinguish 2 or more instances of the browser
300
          mBrowserView->setBrowserModel(mModel);
301
          mBrowserView->setModel(mProxyModel);
302
  }
303

    
304
  for ( int i = 0; i < mModel->rowCount( index ); i++ )
305
  {
306
    QModelIndex idx = mModel->index( i, 0, index );
307
    QModelIndex proxyIdx = mProxyModel->mapFromSource( idx );
308
    QgsDataItem *child = mModel->dataItem( idx );
309

    
310
    // Check also expanded descendants so that the whole expanded path does not get collapsed if one item is collapsed.
311
    // Fast items (usually root items) are refreshed so that when collapsed, it is obvious they are if empty (no expand symbol).
312
    if ( mBrowserView->isExpanded( proxyIdx ) || mBrowserView->hasExpandedDescendant( proxyIdx ) || ( child && child->capabilities2() & QgsDataItem::Fast ) )
313
    {
314
      refreshModel( idx );
315
    }
316
    else
317
    {
318
      if ( child && ( child->capabilities2() & QgsDataItem::Fertile ) )
319
      {
320
        child->depopulate();
321
      }
322
    }
323
  }
324
}
325

    
326
void QgsBrowserDockWidget::addLayer( QgsLayerItem *layerItem )
327
{
328
  if ( !layerItem )
329
    return;
330

    
331
  QgsMimeDataUtils::UriList list;
332
  list << layerItem->mimeUri();
333
  emit handleDropUriList( list );
334
}
335

    
336
void QgsBrowserDockWidget::addLayerAtIndex( const QModelIndex &index )
337
{
338
  QgsDebugMsg( QString( "rowCount() = %1" ).arg( mModel->rowCount( mProxyModel->mapToSource( index ) ) ) );
339
  QgsDataItem *item = mModel->dataItem( mProxyModel->mapToSource( index ) );
340

    
341
  if ( item && item->type() == QgsDataItem::Project )
342
  {
343
    QgsProjectItem *projectItem = qobject_cast<QgsProjectItem *>( item );
344
    if ( projectItem )
345
    {
346
      QApplication::setOverrideCursor( Qt::WaitCursor );
347
      emit openFile( projectItem->path() );
348
      QApplication::restoreOverrideCursor();
349
    }
350
  }
351
  if ( item && item->type() == QgsDataItem::Layer )
352
  {
353
    QgsLayerItem *layerItem = qobject_cast<QgsLayerItem *>( item );
354
    if ( layerItem )
355
    {
356
      QApplication::setOverrideCursor( Qt::WaitCursor );
357
      addLayer( layerItem );
358
      QApplication::restoreOverrideCursor();
359
    }
360
  }
361
}
362

    
363
void QgsBrowserDockWidget::addSelectedLayers()
364
{
365
  QApplication::setOverrideCursor( Qt::WaitCursor );
366

    
367
  // get a sorted list of selected indexes
368
  QModelIndexList list = mBrowserView->selectionModel()->selectedIndexes();
369
  std::sort( list.begin(), list.end() );
370

    
371
  // If any of the layer items are QGIS we just open and exit the loop
372
  Q_FOREACH ( const QModelIndex &index, list )
373
  {
374
    QgsDataItem *item = mModel->dataItem( mProxyModel->mapToSource( index ) );
375
    if ( item && item->type() == QgsDataItem::Project )
376
    {
377
      QgsProjectItem *projectItem = qobject_cast<QgsProjectItem *>( item );
378
      if ( projectItem )
379
        emit openFile( projectItem->path() );
380

    
381
      QApplication::restoreOverrideCursor();
382
      return;
383
    }
384
  }
385

    
386
  // add items in reverse order so they are in correct order in the layers dock
387
  for ( int i = list.size() - 1; i >= 0; i-- )
388
  {
389
    QgsDataItem *item = mModel->dataItem( mProxyModel->mapToSource( list[i] ) );
390
    if ( item && item->type() == QgsDataItem::Layer )
391
    {
392
      QgsLayerItem *layerItem = qobject_cast<QgsLayerItem *>( item );
393
      if ( layerItem )
394
        addLayer( layerItem );
395
    }
396
  }
397

    
398
  QApplication::restoreOverrideCursor();
399
}
400

    
401
void QgsBrowserDockWidget::hideItem()
402
{
403
  QModelIndex index = mProxyModel->mapToSource( mBrowserView->currentIndex() );
404
  QgsDataItem *item = mModel->dataItem( index );
405
  if ( ! item )
406
    return;
407

    
408
  if ( item->type() == QgsDataItem::Directory )
409
  {
410
    mModel->hidePath( item );
411
  }
412
}
413

    
414
void QgsBrowserDockWidget::showProperties()
415
{
416
  QModelIndex index = mProxyModel->mapToSource( mBrowserView->currentIndex() );
417
  QgsDataItem *item = mModel->dataItem( index );
418
  if ( ! item )
419
    return;
420

    
421
  if ( item->type() == QgsDataItem::Layer || item->type() == QgsDataItem::Directory )
422
  {
423
    QgsBrowserPropertiesDialog *dialog = new QgsBrowserPropertiesDialog( settingsSection(), this );
424
    dialog->setItem( item );
425
    dialog->show();
426
  }
427
}
428

    
429
void QgsBrowserDockWidget::toggleFastScan()
430
{
431
  QModelIndex index = mProxyModel->mapToSource( mBrowserView->currentIndex() );
432
  QgsDataItem *item = mModel->dataItem( index );
433
  if ( ! item )
434
    return;
435

    
436
  if ( item->type() == QgsDataItem::Directory )
437
  {
438
    QgsSettings settings;
439
    QStringList fastScanDirs = settings.value( QStringLiteral( "qgis/scanItemsFastScanUris" ),
440
                               QStringList() ).toStringList();
441
    int idx = fastScanDirs.indexOf( item->path() );
442
    if ( idx != -1 )
443
    {
444
      fastScanDirs.removeAt( idx );
445
    }
446
    else
447
    {
448
      fastScanDirs << item->path();
449
    }
450
    settings.setValue( QStringLiteral( "qgis/scanItemsFastScanUris" ), fastScanDirs );
451
  }
452
}
453

    
454
void QgsBrowserDockWidget::showFilterWidget( bool visible )
455
{
456
  mWidgetFilter->setVisible( visible );
457
  if ( ! visible )
458
  {
459
    mLeFilter->setText( QString() );
460
    setFilter();
461
  }
462
  else
463
  {
464
    mLeFilter->setFocus();
465
  }
466
}
467

    
468
void QgsBrowserDockWidget::setFilter()
469
{
470
  QString filter = mLeFilter->text();
471
  if ( mProxyModel )
472
    mProxyModel->setFilter( filter );
473
}
474

    
475
void QgsBrowserDockWidget::updateProjectHome()
476
{
477
  if ( mModel )
478
    mModel->updateProjectHome();
479
}
480

    
481
void QgsBrowserDockWidget::setFilterSyntax( QAction *action )
482
{
483
  if ( !action || ! mProxyModel )
484
    return;
485
  mProxyModel->setFilterSyntax( action->data().toString() );
486
}
487

    
488
void QgsBrowserDockWidget::setCaseSensitive( bool caseSensitive )
489
{
490
  if ( ! mProxyModel )
491
    return;
492
  mProxyModel->setCaseSensitive( caseSensitive );
493
}
494

    
495
int QgsBrowserDockWidget::selectedItemsCount()
496
{
497
  QItemSelectionModel *selectionModel = mBrowserView->selectionModel();
498
  if ( selectionModel )
499
  {
500
    return selectionModel->selectedIndexes().size();
501
  }
502
  return 0;
503
}
504

    
505
void QgsBrowserDockWidget::selectionChanged( const QItemSelection &selected, const QItemSelection &deselected )
506
{
507
  Q_UNUSED( selected );
508
  Q_UNUSED( deselected );
509
  if ( mPropertiesWidgetEnabled )
510
  {
511
    setPropertiesWidget();
512
  }
513
}
514

    
515
void QgsBrowserDockWidget::clearPropertiesWidget()
516
{
517
  while ( mPropertiesLayout->count() > 0 )
518
  {
519
    delete mPropertiesLayout->itemAt( 0 )->widget();
520
  }
521
  mPropertiesWidget->setVisible( false );
522
}
523

    
524
void QgsBrowserDockWidget::setPropertiesWidget()
525
{
526
  clearPropertiesWidget();
527
  QItemSelectionModel *selectionModel = mBrowserView->selectionModel();
528
  if ( selectionModel )
529
  {
530
    QModelIndexList indexes = selectionModel->selectedIndexes();
531
    if ( indexes.size() == 1 )
532
    {
533
      QModelIndex index = mProxyModel->mapToSource( indexes.value( 0 ) );
534
      QgsDataItem *item = mModel->dataItem( index );
535
      QgsBrowserPropertiesWidget *propertiesWidget = QgsBrowserPropertiesWidget::createWidget( item, mPropertiesWidget );
536
      if ( propertiesWidget )
537
      {
538
        propertiesWidget->setCondensedMode( true );
539
        mPropertiesLayout->addWidget( propertiesWidget );
540
      }
541
    }
542
  }
543
  mPropertiesWidget->setVisible( mPropertiesLayout->count() > 0 );
544
}
545

    
546
void QgsBrowserDockWidget::enablePropertiesWidget( bool enable )
547
{
548
  mPropertiesWidgetEnabled = enable;
549
  if ( enable && selectedItemsCount() == 1 )
550
  {
551
    setPropertiesWidget();
552
  }
553
  else
554
  {
555
    clearPropertiesWidget();
556
  }
557
}
558

    
559
void QgsBrowserDockWidget::splitterMoved()
560
{
561
  QList<int> sizes = mSplitter->sizes();
562
  float total = sizes.value( 0 ) + sizes.value( 1 );
563
  mPropertiesWidgetHeight = total > 0 ? sizes.value( 1 ) / total : 0;
564
}