1 /* This file is (c) 2017 Abs62
2  * Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
3 
4 #ifndef __FAVORITIESPANEWIDGET_HH__INCLUDED__
5 #define __FAVORITIESPANEWIDGET_HH__INCLUDED__
6 
7 #include <QWidget>
8 #include <QSize>
9 #include <QAbstractItemModel>
10 #include <QLabel>
11 #include <QHBoxLayout>
12 #include <QMenu>
13 #include <QDomNode>
14 #include <QList>
15 #include <QMimeData>
16 
17 #include <config.hh>
18 #include "delegate.hh"
19 #include "treeview.hh"
20 
21 class FavoritesModel;
22 
23 class FavoritesPaneWidget : public QWidget
24 {
25   Q_OBJECT
26 public:
FavoritesPaneWidget(QWidget * parent=0)27   FavoritesPaneWidget( QWidget * parent = 0 ): QWidget( parent ),
28     itemSelectionChanged( false )
29   , listItemDelegate( 0 )
30   , m_favoritesModel( 0 )
31   , timerId( 0 )
32   {}
33 
34   virtual ~FavoritesPaneWidget();
35 
sizeHint() const36   virtual QSize sizeHint() const
37   { return QSize( 204, 204 ); }
38 
39   void setUp( Config::Class * cfg, QMenu * menu );
40 
41   void addHeadword( QString const & path, QString const & headword );
42 
43   bool removeHeadword( QString const & path, QString const & headword );
44 
45   // Export/import Favorites
46   void getDataInXml( QByteArray & dataStr );
47   void getDataInPlainText( QString & dataStr );
48   bool setDataFromXml( QString const & dataStr );
49 
setFocusOnTree()50   void setFocusOnTree()
51   { m_favoritesTree->setFocus(); }
52 
53   // Set interval for periodical save
54   void setSaveInterval( unsigned interval );
55 
56   // Return true if headwors is already presented in Favorites
57   bool isHeadwordPresent( QString const & path, QString const & headword );
58 
59   void saveData();
60 
61 signals:
62   void favoritesItemRequested( QString const & word, QString const & faforitesFolder );
63 
64 protected:
65   virtual void timerEvent( QTimerEvent * ev );
66 
67 private slots:
68   void emitFavoritesItemRequested(QModelIndex const &);
69   void onSelectionChanged(QItemSelection const & selection);
70   void onItemClicked(QModelIndex const & idx);
71   void showCustomMenu(QPoint const & pos);
72   void deleteSelectedItems();
73   void copySelectedItems();
74   void addFolder();
75 
76 private:
77   virtual bool eventFilter( QObject *, QEvent * );
78 
79   Config::Class * m_cfg ;
80   TreeView * m_favoritesTree;
81   QMenu * m_favoritesMenu;
82   QAction * m_deleteSelectedAction;
83   QAction * m_separator;
84   QAction * m_copySelectedToClipboard;
85   QAction * m_addFolder;
86 
87   QWidget favoritesPaneTitleBar;
88   QHBoxLayout favoritesPaneTitleBarLayout;
89   QLabel favoritesLabel;
90 
91   /// needed to avoid multiple notifications
92   /// when selecting items via mouse and keyboard
93   bool itemSelectionChanged;
94 
95   WordListItemDelegate * listItemDelegate;
96   FavoritesModel * m_favoritesModel;
97 
98   int timerId;
99 };
100 
101 
102 class TreeItem
103 {
104 public:
105   enum Type { Word, Folder, Root };
106 
107   TreeItem( const QVariant &data, TreeItem *parent = 0, Type type_ = Word );
108   ~TreeItem();
109 
110   void appendChild( TreeItem * child );
111 
112   void insertChild( int row, TreeItem * item );
113 
114   // Remove child from list and delete it
115   void deleteChild( int row );
116 
117   TreeItem * child( int row ) const;
118   int childCount() const;
119   QVariant data() const;
120   void setData( const QVariant & newData );
121   int row() const;
122   TreeItem * parent();
123 
type() const124   Type type() const
125   { return m_type; }
126 
127   Qt::ItemFlags flags() const;
128 
setExpanded(bool expanded)129   void setExpanded( bool expanded )
130   { m_expanded = expanded; }
131 
isExpanded() const132   bool isExpanded() const
133   { return m_expanded; }
134 
135   // Full path from root folder
136   QString fullPath() const;
137 
138   // Duplicate item with all childs
139   TreeItem * duplicateItem( TreeItem * newParent ) const;
140 
141   // Check if item is ancestor of this element
142   bool haveAncestor( TreeItem * item );
143 
144   // Check if same item already presented between childs
145   bool haveSameItem( TreeItem * item, bool allowSelf );
146 
147   // Retrieve text from all childs
148   QStringList getTextFromAllChilds() const;
149 
150 private:
151   QList< TreeItem * > childItems;
152   QVariant itemData;
153   TreeItem *parentItem;
154   Type m_type;
155   bool m_expanded;
156 };
157 
158 class FavoritesModel : public QAbstractItemModel
159 {
160   Q_OBJECT
161 public:
162   explicit FavoritesModel( QString favoritesFilename, QObject * parent = 0 );
163   ~FavoritesModel();
164 
165   QVariant data( const QModelIndex &index, int role ) const;
166   Qt::ItemFlags flags( const QModelIndex &index ) const;
167   QVariant headerData( int section, Qt::Orientation orientation,
168                        int role = Qt::DisplayRole ) const;
169   QModelIndex index( int row, int column,
170                      const QModelIndex &parent = QModelIndex() ) const;
171   QModelIndex parent( const QModelIndex &index ) const;
172   int rowCount( const QModelIndex &parent = QModelIndex() ) const;
173   int columnCount( const QModelIndex &parent = QModelIndex() ) const;
174   bool removeRows( int row, int count, const QModelIndex &parent );
175   bool setData( const QModelIndex &index, const QVariant &value, int role );
176 
177   // Drag & drop support
178   Qt::DropActions supportedDropActions() const;
179   QStringList mimeTypes() const;
180   QMimeData *mimeData(const QModelIndexList &indexes) const;
181   bool dropMimeData(const QMimeData *data, Qt::DropAction action,
182                     int row, int column, const QModelIndex &par);
183 
184   // Restore nodes expanded state after data loading
185   void checkNodeForExpand( const TreeItem * item, const QModelIndex &parent );
186   void checkAllNodesForExpand();
187 
188   // Retrieve text data for indexes
189   QStringList getTextForIndexes( QModelIndexList const & idxList ) const;
190 
191   // Delete items for indexes
192   void removeItemsForIndexes( QModelIndexList const & idxList );
193 
194   // Add new folder beside item and return its index
195   // or empty index if fail
196   QModelIndex addNewFolder( QModelIndex const & idx );
197 
198   // Add new headword to given folder
199   // return false if it already exists there
200   bool addNewHeadword( QString const & path, QString const & headword );
201 
202   // Remove headword from given folder
203   // return false if failed
204   bool removeHeadword( QString const & path, QString const & headword );
205 
206   // Return true if headwors is already presented in Favorites
207   bool isHeadwordPresent( QString const & path, QString const & headword );
208 
209   // Return path in the tree to item
210   QString pathToItem( QModelIndex const & idx );
211 
itemType(QModelIndex const & idx)212   TreeItem::Type itemType( QModelIndex const & idx )
213   { return getItem( idx )->type(); }
214 
215   // Export/import Favorites
216   void getDataInXml( QByteArray & dataStr );
217   void getDataInPlainText( QString & dataStr );
218   bool setDataFromXml( QString const & dataStr );
219 
220   void saveData();
221 
222 public slots:
223   void itemCollapsed ( const QModelIndex & index );
224   void itemExpanded ( const QModelIndex & index );
225 
226 signals:
227   void expandItem( const QModelIndex & index );
228 
229 protected:
230   void readData();
231   void addFolder( TreeItem * parent, QDomNode & node );
232   void storeFolder( TreeItem * folder, QDomNode & node );
233 
234   // Find item in folder
235   QModelIndex findItemInFolder( QString const & itemName, int itemType,
236                                 QModelIndex const & parentIdx );
237 
238   TreeItem *getItem( const QModelIndex &index ) const;
239 
240   // Find folder with given name or create it if folder not exist
241   QModelIndex forceFolder( QString const & name, QModelIndex const & parentIdx );
242 
243   // Add headword to given folder
244   // return false if such headwordalready exists
245   bool addHeadword( QString const & word, QModelIndex const & parentIdx );
246 
247   // Return tree level for item
248   int level( QModelIndex const & idx );
249 
250 private:
251   QString m_favoritesFilename;
252   TreeItem * rootItem;
253   QDomDocument dom;
254   bool dirty;
255 };
256 
257 #define FAVORITES_MIME_TYPE "application/x-goldendict-tree-items"
258 
259 class FavoritesMimeData : public QMimeData
260 {
261   Q_OBJECT
262 public:
FavoritesMimeData()263   FavoritesMimeData() : QMimeData()
264   {}
265 
formats() const266   virtual QStringList formats() const
267   { return QStringList( QString::fromLatin1( FAVORITES_MIME_TYPE ) ); }
268 
hasFormat(const QString & mimetype) const269   virtual bool hasFormat(const QString & mimetype) const
270   { return mimetype.compare( QString::fromLatin1( FAVORITES_MIME_TYPE ) ) == 0; }
271 
setIndexesList(QModelIndexList const & list)272   void setIndexesList( QModelIndexList const & list )
273   { indexes.clear(); indexes = list; }
274 
getIndexesList() const275   QModelIndexList const & getIndexesList() const
276   { return indexes; }
277 
278 private:
279   QStringList mimeFormats;
280   QModelIndexList indexes;
281 };
282 
283 #endif // __FAVORITIESPANEWIDGET_HH__INCLUDED__
284