1 /***************************************************************************
2                              qgslayoutitemslistview.cpp
3                              --------------------------
4     Date                 : October 2017
5     Copyright            : (C) 2017 Nyall Dawson
6     Email                : nyall dot dawson 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 
16 #include "qgslayoutitemslistview.h"
17 #include "qgslayout.h"
18 #include "qgslayoutmodel.h"
19 #include "qgslayoutdesignerinterface.h"
20 #include "qgslayoutview.h"
21 #include <QHeaderView>
22 #include <QMenu>
23 #include <QMouseEvent>
24 
25 
QgsLayoutItemsListViewModel(QgsLayoutModel * model,QObject * parent)26 QgsLayoutItemsListViewModel::QgsLayoutItemsListViewModel( QgsLayoutModel *model, QObject *parent )
27   : QSortFilterProxyModel( parent )
28   , mModel( model )
29 {
30   setSourceModel( mModel );
31 }
32 
itemFromIndex(const QModelIndex & index) const33 QgsLayoutItem *QgsLayoutItemsListViewModel::itemFromIndex( const QModelIndex &index ) const
34 {
35   return mModel->itemFromIndex( mapToSource( index ) );
36 }
37 
setSelected(const QModelIndex & index)38 void QgsLayoutItemsListViewModel::setSelected( const QModelIndex &index )
39 {
40   mModel->setSelected( mapToSource( index ) );
41 }
42 
filterAcceptsRow(int sourceRow,const QModelIndex &) const43 bool QgsLayoutItemsListViewModel::filterAcceptsRow( int sourceRow, const QModelIndex & ) const
44 {
45   if ( sourceRow == 0 )
46     return false; // hide empty null item row
47   return true;
48 }
49 
data(const QModelIndex & index,int role) const50 QVariant QgsLayoutItemsListViewModel::data( const QModelIndex &index, int role ) const
51 {
52   if ( !index.isValid() )
53     return QVariant();
54 
55   QgsLayoutItem *item = itemFromIndex( index );
56   if ( !item )
57   {
58     return QVariant();
59   }
60 
61   if ( role == Qt::FontRole )
62   {
63     if ( index.column() == QgsLayoutModel::ItemId && item->isSelected() )
64     {
65       //draw name of selected items in bold
66       QFont boldFont;
67       boldFont.setBold( true );
68       return boldFont;
69     }
70   }
71 
72   return QSortFilterProxyModel::data( index, role );
73 }
74 
75 
76 //
77 // QgsLayoutItemsListView
78 //
79 
QgsLayoutItemsListView(QWidget * parent,QgsLayoutDesignerInterface * designer)80 QgsLayoutItemsListView::QgsLayoutItemsListView( QWidget *parent, QgsLayoutDesignerInterface *designer )
81   : QTreeView( parent )
82   , mDesigner( designer )
83 {
84   setColumnWidth( 0, 30 );
85   setColumnWidth( 1, 30 );
86   setDragEnabled( true );
87   setAcceptDrops( true );
88   setDropIndicatorShown( true );
89   setDragDropMode( QAbstractItemView::InternalMove );
90   setContextMenuPolicy( Qt::CustomContextMenu );
91   setIndentation( 0 );
92   connect( this, &QWidget::customContextMenuRequested, this, &QgsLayoutItemsListView::showContextMenu );
93 }
94 
setCurrentLayout(QgsLayout * layout)95 void QgsLayoutItemsListView::setCurrentLayout( QgsLayout *layout )
96 {
97   mLayout = layout;
98   mModel = new QgsLayoutItemsListViewModel( layout->itemsModel(), this );
99   setModel( mModel );
100 
101   header()->setSectionResizeMode( 0, QHeaderView::Fixed );
102   header()->setSectionResizeMode( 1, QHeaderView::Fixed );
103   setColumnWidth( 0, Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'x' ) * 4 );
104   setColumnWidth( 1, Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'x' ) * 4 );
105   header()->setSectionsMovable( false );
106 
107   connect( selectionModel(), &QItemSelectionModel::currentChanged, mModel, &QgsLayoutItemsListViewModel::setSelected );
108 }
109 
showContextMenu(QPoint point)110 void QgsLayoutItemsListView::showContextMenu( QPoint point )
111 {
112   if ( !mModel )
113     return;
114   const QModelIndex index = indexAt( point );
115   QgsLayoutItem *item = mModel->itemFromIndex( index );
116   if ( !item )
117     return;
118 
119   QMenu *menu = new QMenu( this );
120 
121   QAction *copyAction = new QAction( tr( "Copy Item" ), menu );
122   connect( copyAction, &QAction::triggered, this, [this, item]()
123   {
124     mDesigner->view()->copyItems( QList< QgsLayoutItem * >() << item, QgsLayoutView::ClipboardCopy );
125   } );
126   menu->addAction( copyAction );
127   QAction *deleteAction = new QAction( tr( "Delete Item" ), menu );
128   connect( deleteAction, &QAction::triggered, this, [this, item]()
129   {
130     mDesigner->view()->deleteItems( QList< QgsLayoutItem * >() << item );
131   } );
132   menu->addAction( deleteAction );
133   menu->addSeparator();
134 
135   QAction *itemPropertiesAction = new QAction( tr( "Item Properties…" ), menu );
136   connect( itemPropertiesAction, &QAction::triggered, this, [this, item]()
137   {
138     mDesigner->showItemOptions( item, true );
139   } );
140   menu->addAction( itemPropertiesAction );
141 
142   menu->popup( mapToGlobal( point ) );
143 }
144