1 | /* This file is part of the Kate project. |
2 | * Based on the snippet plugin from KDevelop 4. |
3 | * |
4 | * Copyright (C) 2007 Robert Gruber <rgruber@users.sourceforge.net> |
5 | * Copyright (C) 2010 Milian Wolff <mail@milianw.de> |
6 | * Copyright (C) 2012 Christoph Cullmann <cullmann@kde.org> |
7 | * |
8 | * This library is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU Library General Public |
10 | * License as published by the Free Software Foundation; either |
11 | * version 2 of the License, or (at your option) any later version. |
12 | * |
13 | * This library is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * Library General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU Library General Public License |
19 | * along with this library; see the file COPYING.LIB. If not, write to |
20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
21 | * Boston, MA 02110-1301, USA. |
22 | */ |
23 | |
24 | #include "snippetview.h" |
25 | |
26 | #include <QContextMenuEvent> |
27 | #include <KMenu> |
28 | #include <KMessageBox> |
29 | #include <KAction> |
30 | #include <KDebug> |
31 | |
32 | #include "snippet.h" |
33 | #include "katesnippetglobal.h" |
34 | #include "snippetrepository.h" |
35 | #include "snippetstore.h" |
36 | #include "editrepository.h" |
37 | #include "editsnippet.h" |
38 | #include "snippetfilterproxymodel.h" |
39 | |
40 | #include <KGlobalSettings> |
41 | |
42 | #include <KNS3/DownloadDialog> |
43 | #include <knewstuff3/uploaddialog.h> |
44 | |
45 | SnippetView::SnippetView(KateSnippetGlobal* plugin, QWidget* parent) |
46 | : QWidget(parent), Ui::SnippetViewBase(), m_plugin(plugin) |
47 | { |
48 | Ui::SnippetViewBase::setupUi(this); |
49 | |
50 | setWindowTitle(i18n("Snippets" )); |
51 | setWindowIcon (KIcon("document-new" )); |
52 | |
53 | connect(filterText, SIGNAL(clearButtonClicked()), |
54 | this, SLOT(slotFilterChanged())); |
55 | connect(filterText, SIGNAL(textChanged(QString)), |
56 | this, SLOT(slotFilterChanged())); |
57 | |
58 | snippetTree->setContextMenuPolicy( Qt::CustomContextMenu ); |
59 | snippetTree->viewport()->installEventFilter( this ); |
60 | connect(snippetTree, SIGNAL(customContextMenuRequested(QPoint)), |
61 | this, SLOT(contextMenu(QPoint))); |
62 | |
63 | m_proxy = new SnippetFilterProxyModel(this); |
64 | |
65 | m_proxy->setSourceModel( SnippetStore::self() ); |
66 | |
67 | snippetTree->setModel( m_proxy ); |
68 | // snippetTree->setModel( SnippetStore::instance() ); |
69 | |
70 | snippetTree->header()->hide(); |
71 | |
72 | m_addRepoAction = new KAction(KIcon("folder-new" ), i18n("Add Repository" ), this); |
73 | connect(m_addRepoAction, SIGNAL(triggered()), this, SLOT(slotAddRepo())); |
74 | addAction(m_addRepoAction); |
75 | m_editRepoAction = new KAction(KIcon("folder-txt" ), i18n("Edit Repository" ), this); |
76 | connect(m_editRepoAction, SIGNAL(triggered()), this, SLOT(slotEditRepo())); |
77 | addAction(m_editRepoAction); |
78 | m_removeRepoAction = new KAction(KIcon("edit-delete" ), i18n("Remove Repository" ), this); |
79 | connect(m_removeRepoAction, SIGNAL(triggered()), this, SLOT(slotRemoveRepo())); |
80 | addAction(m_removeRepoAction); |
81 | |
82 | m_putNewStuffAction = new KAction(KIcon("get-hot-new-stuff" ), i18n("Publish Repository" ), this); |
83 | connect(m_putNewStuffAction, SIGNAL(triggered()), this, SLOT(slotSnippetToGHNS())); |
84 | addAction(m_putNewStuffAction); |
85 | |
86 | QAction* separator = new QAction(this); |
87 | separator->setSeparator(true); |
88 | addAction(separator); |
89 | |
90 | m_addSnippetAction = new KAction(KIcon("document-new" ), i18n("Add Snippet" ), this); |
91 | connect(m_addSnippetAction, SIGNAL(triggered()), this, SLOT(slotAddSnippet())); |
92 | addAction(m_addSnippetAction); |
93 | m_editSnippetAction = new KAction(KIcon("document-edit" ), i18n("Edit Snippet" ), this); |
94 | connect(m_editSnippetAction, SIGNAL(triggered()), this, SLOT(slotEditSnippet())); |
95 | addAction(m_editSnippetAction); |
96 | m_removeSnippetAction = new KAction(KIcon("document-close" ), i18n("Remove Snippet" ), this); |
97 | connect(m_removeSnippetAction, SIGNAL(triggered()), this, SLOT(slotRemoveSnippet())); |
98 | addAction(m_removeSnippetAction); |
99 | |
100 | addAction(separator); |
101 | |
102 | m_getNewStuffAction = new KAction(KIcon("get-hot-new-stuff" ), i18n("Get New Snippets" ), this); |
103 | connect(m_getNewStuffAction, SIGNAL(triggered()), this, SLOT(slotGHNS())); |
104 | addAction(m_getNewStuffAction); |
105 | |
106 | connect(snippetTree->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(validateActions())); |
107 | validateActions(); |
108 | } |
109 | |
110 | SnippetView::~SnippetView() |
111 | { |
112 | } |
113 | |
114 | void SnippetView::validateActions() |
115 | { |
116 | |
117 | QStandardItem* item = currentItem(); |
118 | |
119 | Snippet* selectedSnippet = dynamic_cast<Snippet*>( item ); |
120 | SnippetRepository* selectedRepo = dynamic_cast<SnippetRepository*>( item ); |
121 | |
122 | m_addRepoAction->setEnabled(true); |
123 | m_editRepoAction->setEnabled(selectedRepo); |
124 | m_removeRepoAction->setEnabled(selectedRepo); |
125 | m_putNewStuffAction->setEnabled(selectedRepo); |
126 | |
127 | m_addSnippetAction->setEnabled(selectedRepo || selectedSnippet); |
128 | m_editSnippetAction->setEnabled(selectedSnippet); |
129 | m_removeSnippetAction->setEnabled(selectedSnippet); |
130 | } |
131 | |
132 | QStandardItem* SnippetView::currentItem() |
133 | { |
134 | ///TODO: support multiple selected items |
135 | QModelIndex index = snippetTree->currentIndex(); |
136 | index = m_proxy->mapToSource(index); |
137 | return SnippetStore::self()->itemFromIndex( index ); |
138 | } |
139 | |
140 | void SnippetView::slotSnippetClicked (const QModelIndex & index) |
141 | { |
142 | QStandardItem* item = SnippetStore::self()->itemFromIndex( m_proxy->mapToSource(index) ); |
143 | if (!item) |
144 | return; |
145 | |
146 | Snippet* snippet = dynamic_cast<Snippet*>( item ); |
147 | if (!snippet) |
148 | return; |
149 | |
150 | m_plugin->insertSnippet( snippet ); |
151 | } |
152 | |
153 | void SnippetView::contextMenu (const QPoint& pos) |
154 | { |
155 | QModelIndex index = snippetTree->indexAt( pos ); |
156 | index = m_proxy->mapToSource(index); |
157 | QStandardItem* item = SnippetStore::self()->itemFromIndex( index ); |
158 | if (!item) { |
159 | // User clicked into an empty place of the tree |
160 | KMenu menu(this); |
161 | menu.addTitle(i18n("Snippets" )); |
162 | |
163 | menu.addAction(m_addRepoAction); |
164 | menu.addAction(m_getNewStuffAction); |
165 | |
166 | menu.exec(snippetTree->mapToGlobal(pos)); |
167 | } else if (Snippet* snippet = dynamic_cast<Snippet*>( item )) { |
168 | KMenu menu(this); |
169 | menu.addTitle(i18n("Snippet: %1" , snippet->text())); |
170 | |
171 | menu.addAction(m_editSnippetAction); |
172 | menu.addAction(m_removeSnippetAction); |
173 | |
174 | menu.exec(snippetTree->mapToGlobal(pos)); |
175 | } else if (SnippetRepository* repo = dynamic_cast<SnippetRepository*>( item )) { |
176 | KMenu menu(this); |
177 | menu.addTitle(i18n("Repository: %1" , repo->text())); |
178 | |
179 | menu.addAction(m_editRepoAction); |
180 | menu.addAction(m_removeRepoAction); |
181 | menu.addAction(m_putNewStuffAction); |
182 | menu.addSeparator(); |
183 | |
184 | menu.addAction(m_addSnippetAction); |
185 | |
186 | menu.exec(snippetTree->mapToGlobal(pos)); |
187 | } |
188 | } |
189 | |
190 | void SnippetView::slotEditSnippet() |
191 | { |
192 | QStandardItem* item = currentItem(); |
193 | if (!item) |
194 | return; |
195 | |
196 | Snippet* snippet = dynamic_cast<Snippet*>( item ); |
197 | if (!snippet) |
198 | return; |
199 | |
200 | SnippetRepository* repo = dynamic_cast<SnippetRepository*>( item->parent() ); |
201 | if (!repo) |
202 | return; |
203 | |
204 | EditSnippet dlg(repo, snippet, this); |
205 | dlg.exec(); |
206 | } |
207 | |
208 | void SnippetView::slotAddSnippet() |
209 | { |
210 | QStandardItem* item = currentItem(); |
211 | if (!item) |
212 | return; |
213 | |
214 | SnippetRepository* repo = dynamic_cast<SnippetRepository*>( item ); |
215 | if (!repo) { |
216 | repo = dynamic_cast<SnippetRepository*>( item->parent() ); |
217 | if ( !repo ) |
218 | return; |
219 | } |
220 | |
221 | EditSnippet dlg(repo, 0, this); |
222 | dlg.exec(); |
223 | } |
224 | |
225 | void SnippetView::slotRemoveSnippet() |
226 | { |
227 | QStandardItem* item = currentItem(); |
228 | if (!item) |
229 | return; |
230 | |
231 | SnippetRepository* repo = dynamic_cast<SnippetRepository*>( item->parent() ); |
232 | if (!repo) |
233 | return; |
234 | |
235 | int ans = KMessageBox::warningContinueCancel( |
236 | QApplication::activeWindow(), |
237 | i18n("Do you really want to delete the snippet \"%1\"?" , item->text()) |
238 | ); |
239 | if ( ans == KMessageBox::Continue ) { |
240 | item->parent()->removeRow(item->row()); |
241 | repo->save(); |
242 | } |
243 | } |
244 | |
245 | void SnippetView::slotAddRepo() |
246 | { |
247 | EditRepository dlg(0, this); |
248 | dlg.exec(); |
249 | } |
250 | |
251 | void SnippetView::slotEditRepo() |
252 | { |
253 | QStandardItem* item = currentItem(); |
254 | if (!item) |
255 | return; |
256 | |
257 | SnippetRepository* repo = dynamic_cast<SnippetRepository*>( item ); |
258 | if (!repo) |
259 | return; |
260 | |
261 | EditRepository dlg(repo, this); |
262 | dlg.exec(); |
263 | } |
264 | |
265 | void SnippetView::slotRemoveRepo() |
266 | { |
267 | QStandardItem* item = currentItem(); |
268 | if (!item) |
269 | return; |
270 | |
271 | SnippetRepository* repo = dynamic_cast<SnippetRepository*>( item ); |
272 | if (!repo) |
273 | return; |
274 | |
275 | int ans = KMessageBox::warningContinueCancel( |
276 | QApplication::activeWindow(), |
277 | i18n("Do you really want to delete the repository \"%1\" with all its snippets?" , repo->text()) |
278 | ); |
279 | if ( ans == KMessageBox::Continue ) { |
280 | repo->remove(); |
281 | } |
282 | } |
283 | |
284 | void SnippetView::slotFilterChanged() |
285 | { |
286 | m_proxy->changeFilter( filterText->text() ); |
287 | } |
288 | |
289 | void SnippetView::slotGHNS() |
290 | { |
291 | KNS3::DownloadDialog dialog("ktexteditor_codesnippets_core.knsrc" , this); |
292 | dialog.exec(); |
293 | foreach ( const KNS3::Entry& entry, dialog.changedEntries() ) { |
294 | foreach ( const QString& path, entry.uninstalledFiles() ) { |
295 | if ( path.endsWith(".xml" ) ) { |
296 | if ( SnippetRepository* repo = SnippetStore::self()->repositoryForFile(path) ) { |
297 | repo->remove(); |
298 | } |
299 | } |
300 | } |
301 | foreach ( const QString& path, entry.installedFiles() ) { |
302 | if ( path.endsWith(".xml" ) ) { |
303 | SnippetStore::self()->appendRow(new SnippetRepository(path)); |
304 | } |
305 | } |
306 | } |
307 | } |
308 | |
309 | void SnippetView::slotSnippetToGHNS() |
310 | { |
311 | QStandardItem* item = currentItem(); |
312 | if ( !item) |
313 | return; |
314 | |
315 | SnippetRepository* repo = dynamic_cast<SnippetRepository*>( item ); |
316 | if ( !repo ) |
317 | return; |
318 | |
319 | KNS3::UploadDialog dialog("ktexteditor_codesnippets_core.knsrc" , this); |
320 | dialog.setUploadFile(KUrl::fromPath(repo->file())); |
321 | dialog.setUploadName(repo->text()); |
322 | dialog.exec(); |
323 | } |
324 | |
325 | bool SnippetView::eventFilter(QObject* obj, QEvent* e) |
326 | { |
327 | // no, listening to activated() is not enough since that would also trigger the edit mode which we _dont_ want here |
328 | // users may still rename stuff via select + F2 though |
329 | if (obj == snippetTree->viewport()) { |
330 | const bool singleClick = KGlobalSettings::singleClick(); |
331 | if ( (!singleClick && e->type() == QEvent::MouseButtonDblClick) || (singleClick && e->type() == QEvent::MouseButtonRelease) ) { |
332 | QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>(e); |
333 | Q_ASSERT(mouseEvent); |
334 | QModelIndex clickedIndex = snippetTree->indexAt(mouseEvent->pos()); |
335 | if (clickedIndex.isValid() && clickedIndex.parent().isValid()) { |
336 | slotSnippetClicked(clickedIndex); |
337 | e->accept(); |
338 | return true; |
339 | } |
340 | } |
341 | } |
342 | return QObject::eventFilter(obj, e); |
343 | } |
344 | |
345 | |
346 | #include "snippetview.moc" |
347 | |