1/* This file is part of the KDE project
2 Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
3 Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
4 Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk>
5 Copyright (C) 2007 Mirko Stocker <me@misto.ch>
6 Copyright (C) 2009 Dominik Haumann <dhaumann 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 version 2 as published by the Free Software Foundation.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21*/
22
23//BEGIN Includes
24#include "katefilebrowser.h"
25#include "katefilebrowser.moc"
26
27#include "katebookmarkhandler.h"
28
29#include <ktexteditor/document.h>
30#include <ktexteditor/view.h>
31
32#include <KActionCollection>
33#include <KActionMenu>
34#include <KConfigGroup>
35#include <KDebug>
36#include <KDirOperator>
37#include <KFilePlacesModel>
38#include <KHistoryComboBox>
39#include <KLocale>
40#include <KToolBar>
41#include <KUrlNavigator>
42#include <QAbstractItemView>
43#include <QDir>
44#include <QLabel>
45#include <QLineEdit>
46#include <QToolButton>
47#include <KMessageBox>
48
49#include <kdeversion.h>
50
51//END Includes
52
53
54KateFileBrowser::KateFileBrowser(Kate::MainWindow *mainWindow,
55 QWidget * parent, const char * name)
56 : KVBox (parent)
57 , m_mainWindow(mainWindow)
58{
59 setObjectName(name);
60
61 m_toolbar = new KToolBar(this);
62 m_toolbar->setMovable(false);
63 m_toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly);
64 m_toolbar->setContextMenuPolicy(Qt::NoContextMenu);
65
66 // includes some actions, but not hooked into the shortcut dialog atm
67 m_actionCollection = new KActionCollection(this);
68 m_actionCollection->addAssociatedWidget(this);
69
70 KFilePlacesModel* model = new KFilePlacesModel(this);
71 m_urlNavigator = new KUrlNavigator(model, KUrl(QDir::homePath()), this);
72 connect(m_urlNavigator, SIGNAL(urlChanged(KUrl)), SLOT(updateDirOperator(KUrl)));
73
74 m_dirOperator = new KDirOperator(KUrl(), this);
75 m_dirOperator->setView(KFile::/* Simple */Detail);
76 m_dirOperator->view()->setSelectionMode(QAbstractItemView::ExtendedSelection);
77 m_dirOperator->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding));
78
79 // Mime filter for the KDirOperator
80 QStringList filter;
81 filter << "text/plain" << "text/html" << "inode/directory";
82 m_dirOperator->setNewFileMenuSupportedMimeTypes(filter);
83
84 setFocusProxy(m_dirOperator);
85 connect(m_dirOperator, SIGNAL(viewChanged(QAbstractItemView*)),
86 this, SLOT(selectorViewChanged(QAbstractItemView*)));
87 connect(m_urlNavigator, SIGNAL(returnPressed()),
88 m_dirOperator, SLOT(setFocus()));
89 // now all actions exist in dir operator and we can use them in the toolbar
90 setupActions();
91 setupToolbar();
92
93 KHBox* filterBox = new KHBox(this);
94
95 QLabel* filterLabel = new QLabel(i18n("Filter:"), filterBox);
96 m_filter = new KHistoryComboBox(true, filterBox);
97 filterLabel->setBuddy(m_filter);
98 m_filter->setMaxCount(10);
99 m_filter->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
100
101 connect(m_filter, SIGNAL(editTextChanged(QString)),
102 SLOT(slotFilterChange(QString)));
103 connect(m_filter, SIGNAL(returnPressed(QString)),
104 m_filter, SLOT(addToHistory(QString)));
105 connect(m_filter, SIGNAL(returnPressed(QString)),
106 m_dirOperator, SLOT(setFocus()));
107
108 connect(m_dirOperator, SIGNAL(urlEntered(KUrl)),
109 this, SLOT(updateUrlNavigator(KUrl)));
110
111 // Connect the bookmark handler
112 connect(m_bookmarkHandler, SIGNAL(openUrl(QString)),
113 this, SLOT(setDir(QString)));
114
115 m_filter->setWhatsThis(i18n("Enter a name filter to limit which files are displayed."));
116
117 connect(m_dirOperator, SIGNAL(fileSelected(KFileItem)), this, SLOT(fileSelected(KFileItem)));
118 connect(m_mainWindow, SIGNAL(viewChanged()), this, SLOT(autoSyncFolder()));
119}
120
121KateFileBrowser::~KateFileBrowser()
122{
123}
124//END Constroctor/Destrctor
125
126//BEGIN Public Methods
127void KateFileBrowser::setupToolbar()
128{
129 KConfigGroup config(KGlobal::config(), "filebrowser");
130 QStringList actions = config.readEntry( "toolbar actions", QStringList() );
131 if ( actions.isEmpty() ) // default toolbar
132 actions << "back" << "forward" << "bookmarks" << "sync_dir" << "configure";
133
134 // remove all actions from the toolbar (there should be none)
135 m_toolbar->clear();
136
137 // now add all actions to the toolbar
138 foreach (const QString& it, actions)
139 {
140 QAction *ac = 0;
141 if (it.isEmpty()) continue;
142 if (it == "bookmarks" || it == "sync_dir" || it == "configure")
143 ac = actionCollection()->action(it);
144 else
145 ac = m_dirOperator->actionCollection()->action(it);
146
147 if (ac)
148 m_toolbar->addAction(ac);
149 }
150}
151
152void KateFileBrowser::readSessionConfig(KConfigBase *config, const QString & name)
153{
154 KConfigGroup cgDir(config, name + ":dir");
155 m_dirOperator->readConfig(cgDir);
156 m_dirOperator->setView(KFile::Default);
157
158 KConfigGroup cg(config, name);
159 m_urlNavigator->setLocationUrl(cg.readPathEntry("location", QDir::homePath()));
160 setDir(cg.readPathEntry("location", QDir::homePath()));
161 m_autoSyncFolder->setChecked(cg.readEntry("auto sync folder", false));
162 m_filter->setHistoryItems(cg.readEntry("filter history", QStringList()), true);
163}
164
165void KateFileBrowser::writeSessionConfig(KConfigBase *config, const QString & name)
166{
167 KConfigGroup cgDir(config, name + ":dir");
168 m_dirOperator->writeConfig(cgDir);
169
170 KConfigGroup cg = KConfigGroup(config, name);
171 cg.writePathEntry("location", m_urlNavigator->locationUrl().url());
172 cg.writeEntry("auto sync folder", m_autoSyncFolder->isChecked());
173 cg.writeEntry("filter history", m_filter->historyItems());
174}
175
176//END Public Methods
177
178//BEGIN Public Slots
179
180void KateFileBrowser::slotFilterChange(const QString & nf)
181{
182 QString f = nf.trimmed();
183 const bool empty = f.isEmpty() || f == "*";
184
185 if (empty) {
186 m_dirOperator->clearFilter();
187 } else {
188 m_dirOperator->setNameFilter(f);
189 }
190
191 m_dirOperator->updateDir();
192}
193
194bool kateFileSelectorIsReadable (const KUrl& url)
195{
196 if (!url.isLocalFile())
197 return true; // what else can we say?
198
199 QDir dir(url.toLocalFile());
200 return dir.exists ();
201}
202
203void KateFileBrowser::setDir(KUrl u)
204{
205 KUrl newurl;
206
207 if (!u.isValid())
208 newurl.setPath(QDir::homePath());
209 else
210 newurl = u;
211
212 QString pathstr = newurl.path(KUrl::AddTrailingSlash);
213 newurl.setPath(pathstr);
214
215 if (!kateFileSelectorIsReadable (newurl))
216 newurl.cd(QString::fromLatin1(".."));
217
218 if (!kateFileSelectorIsReadable (newurl))
219 newurl.setPath(QDir::homePath());
220
221 m_dirOperator->setUrl(newurl, true);
222}
223
224//END Public Slots
225
226//BEGIN Private Slots
227
228void KateFileBrowser::fileSelected(const KFileItem & /*file*/)
229{
230 openSelectedFiles();
231}
232
233void KateFileBrowser::openSelectedFiles()
234{
235 const KFileItemList list = m_dirOperator->selectedItems();
236
237 if (list.count()>20) {
238 if (KMessageBox::questionYesNo(this,i18np("You are trying to open 1 file, are you sure?", "You are trying to open %1 files, are you sure?", list.count()))
239 == KMessageBox::No) return;
240 }
241
242 foreach (const KFileItem& item, list)
243 {
244 m_mainWindow->openUrl(item.url());
245 }
246
247 m_dirOperator->view()->selectionModel()->clear();
248}
249
250
251
252
253void KateFileBrowser::updateDirOperator(const KUrl& u)
254{
255 m_dirOperator->setUrl(u, true);
256}
257
258void KateFileBrowser::updateUrlNavigator(const KUrl& u)
259{
260 m_urlNavigator->setLocationUrl(u);
261}
262
263void KateFileBrowser::setActiveDocumentDir()
264{
265// kDebug(13001)<<"KateFileBrowser::setActiveDocumentDir()";
266 KUrl u = activeDocumentUrl();
267// kDebug(13001)<<"URL: "<<u.pathOrUrl();
268 if (!u.isEmpty())
269 setDir(u.upUrl());
270// kDebug(13001)<<"... setActiveDocumentDir() DONE!";
271}
272
273void KateFileBrowser::autoSyncFolder()
274{
275 if (m_autoSyncFolder->isChecked()) {
276 setActiveDocumentDir();
277 }
278}
279
280
281void KateFileBrowser::selectorViewChanged(QAbstractItemView * newView)
282{
283 newView->setSelectionMode(QAbstractItemView::ExtendedSelection);
284}
285
286//END Private Slots
287
288//BEGIN Protected
289
290KUrl KateFileBrowser::activeDocumentUrl()
291{
292 KTextEditor::View *v = m_mainWindow->activeView();
293 if (v)
294 return v->document()->url();
295 return KUrl();
296}
297
298void KateFileBrowser::setupActions()
299{
300 // bookmarks action!
301 KActionMenu *acmBookmarks = new KActionMenu(KIcon("bookmarks"), i18n("Bookmarks"), this);
302 acmBookmarks->setDelayed(false);
303 m_bookmarkHandler = new KateBookmarkHandler(this, acmBookmarks->menu());
304 acmBookmarks->setShortcutContext(Qt::WidgetWithChildrenShortcut);
305
306 // action for synchronizing the dir operator with the current document path
307 KAction* syncFolder = new KAction(this);
308 syncFolder->setShortcutContext(Qt::WidgetWithChildrenShortcut);
309 syncFolder->setText(i18n("Current Document Folder"));
310 syncFolder->setIcon(KIcon("system-switch-user"));
311 connect(syncFolder, SIGNAL(triggered()), this, SLOT(setActiveDocumentDir()));
312
313 m_actionCollection->addAction("sync_dir", syncFolder);
314 m_actionCollection->addAction("bookmarks", acmBookmarks);
315
316 // section for settings menu
317 KActionMenu *optionsMenu = new KActionMenu(KIcon("configure"), i18n("Options"), this);
318 optionsMenu->setDelayed(false);
319 optionsMenu->addAction(m_dirOperator->actionCollection()->action("short view"));
320 optionsMenu->addAction(m_dirOperator->actionCollection()->action("detailed view"));
321 optionsMenu->addAction(m_dirOperator->actionCollection()->action("tree view"));
322 optionsMenu->addAction(m_dirOperator->actionCollection()->action("detailed tree view"));
323 optionsMenu->addSeparator();
324 optionsMenu->addAction(m_dirOperator->actionCollection()->action("show hidden"));
325
326 // action for synchronising the dir operator with the current document path
327 m_autoSyncFolder = new KAction(this);
328 m_autoSyncFolder->setCheckable(true);
329 m_autoSyncFolder->setText(i18n("Automatically synchronize with current document"));
330 m_autoSyncFolder->setIcon(KIcon("system-switch-user"));
331 connect(m_autoSyncFolder, SIGNAL(triggered()), this, SLOT(autoSyncFolder()));
332 optionsMenu->addAction(m_autoSyncFolder);
333
334 m_actionCollection->addAction("configure", optionsMenu);
335
336 //
337 // Remove all shortcuts due to shortcut clashes (e.g. F5: reload, Ctrl+B: bookmark)
338 // BUGS: #188954, #236368
339 //
340 foreach (QAction* a, m_actionCollection->actions()) {
341 a->setShortcut(QKeySequence());
342 }
343 foreach (QAction* a, m_dirOperator->actionCollection()->actions()) {
344 a->setShortcut(QKeySequence());
345 }
346}
347//END Protected
348
349// kate: space-indent on; indent-width 2; replace-tabs on;
350