1/* This file is part of the KDE project
2 Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
3 Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org>
4 Copyright (C) 2002 Anders Lund <anders.lund@lund.tdcadsl.dk>
5 Copyright (C) 2007 Anders Lund <anders@alweb.dk>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License version 2 as published by the Free Software Foundation.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22#include "kateconsole.h"
23#include "kateconsole.moc"
24
25#include <kicon.h>
26#include <kiconloader.h>
27#include <ktexteditor/document.h>
28#include <ktexteditor/view.h>
29
30#include <kde_terminal_interface.h>
31#include <kshell.h>
32#include <kparts/part.h>
33#include <kaction.h>
34#include <kactioncollection.h>
35#include <KDialog>
36
37#include <kurl.h>
38#include <klibloader.h>
39#include <klocale.h>
40#include <kdebug.h>
41#include <kmessagebox.h>
42
43#include <QShowEvent>
44#include <QLabel>
45#include <QCheckBox>
46#include <QVBoxLayout>
47
48#include <kpluginloader.h>
49#include <kservice.h>
50#include <kaboutdata.h>
51#include <kpluginfactory.h>
52#include <kauthorized.h>
53
54K_PLUGIN_FACTORY(KateKonsoleFactory, registerPlugin<KateKonsolePlugin>();)
55K_EXPORT_PLUGIN(KateKonsoleFactory(KAboutData("katekonsole","katekonsoleplugin",ki18n("Konsole"), "0.1", ki18n("Embedded Konsole"), KAboutData::License_LGPL_V2)) )
56
57KateKonsolePlugin::KateKonsolePlugin( QObject* parent, const QList<QVariant>& ):
58 Kate::Plugin ( (Kate::Application*)parent )
59{
60 m_previousEditorEnv=qgetenv("EDITOR");
61 if (!KAuthorized::authorizeKAction("shell_access"))
62 {
63 KMessageBox::sorry(0, i18n ("You do not have enough karma to access a shell or terminal emulation"));
64 }
65}
66
67KateKonsolePlugin::~KateKonsolePlugin()
68{
69 ::setenv( "EDITOR", m_previousEditorEnv.data(), 1 );
70}
71
72Kate::PluginView *KateKonsolePlugin::createView (Kate::MainWindow *mainWindow)
73{
74 KateKonsolePluginView *view = new KateKonsolePluginView (this, mainWindow);
75 return view;
76}
77
78Kate::PluginConfigPage *KateKonsolePlugin::configPage (uint number, QWidget *parent, const char *name)
79{
80 Q_UNUSED(name)
81 if (number != 0)
82 return 0;
83 return new KateKonsoleConfigPage(parent, this);
84}
85
86QString KateKonsolePlugin::configPageName (uint number) const
87{
88 if (number != 0) return QString();
89 return i18n("Terminal");
90}
91
92QString KateKonsolePlugin::configPageFullName (uint number) const
93{
94 if (number != 0) return QString();
95 return i18n("Terminal Settings");
96}
97
98KIcon KateKonsolePlugin::configPageIcon (uint number) const
99{
100 if (number != 0) return KIcon();
101 return KIcon("utilities-terminal");
102}
103
104void KateKonsolePlugin::readConfig()
105{
106 foreach ( KateKonsolePluginView *view, mViews )
107 view->readConfig();
108}
109
110KateKonsolePluginView::KateKonsolePluginView (KateKonsolePlugin* plugin, Kate::MainWindow *mainWindow)
111 : Kate::PluginView (mainWindow),m_plugin(plugin)
112{
113 // init console
114 QWidget *toolview = mainWindow->createToolView ("kate_private_plugin_katekonsoleplugin", Kate::MainWindow::Bottom, SmallIcon("utilities-terminal"), i18n("Terminal"));
115 m_console = new KateConsole(m_plugin, mainWindow, toolview);
116
117 // register this view
118 m_plugin->mViews.append ( this );
119}
120
121KateKonsolePluginView::~KateKonsolePluginView ()
122{
123 // unregister this view
124 m_plugin->mViews.removeAll (this);
125
126 // cleanup, kill toolview + console
127 QWidget *toolview = m_console->parentWidget();
128 delete m_console;
129 delete toolview;
130}
131
132void KateKonsolePluginView::readConfig()
133{
134 m_console->readConfig();
135}
136
137KateConsole::KateConsole (KateKonsolePlugin* plugin, Kate::MainWindow *mw, QWidget *parent)
138 : KVBox (parent), Kate::XMLGUIClient(KateKonsoleFactory::componentData())
139 , m_part (0)
140 , m_mw (mw)
141 , m_toolView (parent)
142 , m_plugin(plugin)
143{
144 QAction* a = actionCollection()->addAction("katekonsole_tools_pipe_to_terminal");
145 a->setIcon(KIcon("utilities-terminal"));
146 a->setText(i18nc("@action", "&Pipe to Terminal"));
147 connect(a, SIGNAL(triggered()), this, SLOT(slotPipeToConsole()));
148
149 a = actionCollection()->addAction("katekonsole_tools_sync");
150 a->setText(i18nc("@action", "S&ynchronize Terminal with Current Document"));
151 connect(a, SIGNAL(triggered()), this, SLOT(slotManualSync()));
152
153 a = actionCollection()->addAction("katekonsole_tools_toggle_focus");
154 a->setIcon(KIcon("utilities-terminal"));
155 a->setText(i18nc("@action", "&Focus Terminal"));
156 connect(a, SIGNAL(triggered()), this, SLOT(slotToggleFocus()));
157
158 m_mw->guiFactory()->addClient (this);
159
160 readConfig();
161}
162
163KateConsole::~KateConsole ()
164{
165 m_mw->guiFactory()->removeClient (this);
166 if (m_part)
167 disconnect ( m_part, SIGNAL(destroyed()), this, SLOT(slotDestroyed()) );
168}
169
170void KateConsole::loadConsoleIfNeeded()
171{
172 if (m_part) return;
173
174 if (!window() || !parentWidget()) return;
175 if (!window() || !isVisibleTo(window())) return;
176
177 KPluginFactory* factory = 0;
178 KService::Ptr service = KService::serviceByDesktopName("konsolepart");
179 if (service) {
180 factory = KPluginLoader(service->library()).factory();
181 }
182
183 if (!factory) return;
184
185 m_part = static_cast<KParts::ReadOnlyPart *>(factory->create<QObject>(this, this));
186
187 if (!m_part) return;
188
189 // start the terminal
190 qobject_cast<TerminalInterface*>(m_part)->showShellInDir( QString() );
191
192 KGlobal::locale()->insertCatalog("konsole");
193
194 setFocusProxy(m_part->widget());
195 m_part->widget()->show();
196
197 connect ( m_part, SIGNAL(destroyed()), this, SLOT(slotDestroyed()) );
198 connect ( m_part, SIGNAL(overrideShortcut(QKeyEvent*,bool&)),
199 this, SLOT(overrideShortcut(QKeyEvent*,bool&)));
200 slotSync();
201}
202
203void KateConsole::slotDestroyed ()
204{
205 m_part = 0;
206 m_currentPath.clear ();
207
208 // hide the dockwidget
209 if (parentWidget())
210 {
211 m_mw->hideToolView (m_toolView);
212 m_mw->centralWidget()->setFocus ();
213 }
214}
215
216void KateConsole::overrideShortcut (QKeyEvent *, bool &override)
217{
218 /**
219 * let konsole handle all shortcuts
220 */
221 override = true;
222}
223
224void KateConsole::showEvent(QShowEvent *)
225{
226 if (m_part) return;
227
228 loadConsoleIfNeeded();
229}
230
231void KateConsole::cd (const KUrl &url)
232{
233 if (m_currentPath == url.path())
234 return;
235
236 if (!m_part)
237 return;
238
239 m_currentPath = url.path();
240 sendInput("cd " + KShell::quoteArg(m_currentPath) + '\n');
241}
242
243void KateConsole::sendInput( const QString& text )
244{
245 loadConsoleIfNeeded();
246
247 if (!m_part) return;
248
249 TerminalInterface *t = qobject_cast<TerminalInterface *>(m_part);
250
251 if (!t) return;
252
253 t->sendInput (text);
254}
255
256void KateConsole::slotPipeToConsole ()
257{
258 if (KMessageBox::warningContinueCancel
259 (m_mw->window()
260 , i18n ("Do you really want to pipe the text to the console? This will execute any contained commands with your user rights.")
261 , i18n ("Pipe to Terminal?")
262 , KGuiItem(i18n("Pipe to Terminal")), KStandardGuiItem::cancel(), "Pipe To Terminal Warning") != KMessageBox::Continue)
263 return;
264
265 KTextEditor::View *v = m_mw->activeView();
266
267 if (!v)
268 return;
269
270 if (v->selection())
271 sendInput (v->selectionText());
272 else
273 sendInput (v->document()->text());
274}
275
276void KateConsole::slotSync()
277{
278 if (m_mw->activeView() ) {
279 if ( m_mw->activeView()->document()->url().isValid()
280 && m_mw->activeView()->document()->url().isLocalFile() ) {
281 cd(KUrl( m_mw->activeView()->document()->url().directory() ));
282 } else if ( !m_mw->activeView()->document()->url().isEmpty() ) {
283 sendInput( "### " + i18n("Sorry, cannot cd into '%1'", m_mw->activeView()->document()->url().directory() ) + '\n' );
284 }
285 }
286}
287
288void KateConsole::slotManualSync()
289{
290 m_currentPath.clear ();
291 slotSync();
292 if ( ! m_part || ! m_part->widget()->isVisible() )
293 m_mw->showToolView( parentWidget() );
294}
295void KateConsole::slotToggleFocus()
296{
297 QAction *action = actionCollection()->action("katekonsole_tools_toggle_focus");
298 if ( ! m_part ) {
299 m_mw->showToolView( parentWidget() );
300 action->setText( i18n("Defocus Terminal") );
301 return; // this shows and focuses the konsole
302 }
303
304 if ( ! m_part ) return;
305
306 if (m_part->widget()->hasFocus()) {
307 if (m_mw->activeView())
308 m_mw->activeView()->setFocus();
309 action->setText( i18n("Focus Terminal") );
310 } else {
311 // show the view if it is hidden
312 if (parentWidget()->isHidden())
313 m_mw->showToolView( parentWidget() );
314 else // should focus the widget too!
315 m_part->widget()->setFocus( Qt::OtherFocusReason );
316 action->setText( i18n("Defocus Terminal") );
317 }
318}
319
320void KateConsole::readConfig()
321{
322 disconnect( m_mw, SIGNAL(viewChanged()), this, SLOT(slotSync()) );
323 if ( KConfigGroup(KGlobal::config(), "Konsole").readEntry("AutoSyncronize", false) )
324 connect( m_mw, SIGNAL(viewChanged()), SLOT(slotSync()) );
325
326
327 if ( KConfigGroup(KGlobal::config(), "Konsole").readEntry("SetEditor", false) )
328 ::setenv( "EDITOR", "kate -b",1);
329 else
330 ::setenv( "EDITOR", m_plugin->previousEditorEnv().data(), 1 );
331}
332
333KateKonsoleConfigPage::KateKonsoleConfigPage( QWidget* parent, KateKonsolePlugin *plugin )
334 : Kate::PluginConfigPage( parent )
335 , mPlugin( plugin )
336{
337 QVBoxLayout *lo = new QVBoxLayout( this );
338 lo->setSpacing( KDialog::spacingHint() );
339
340 cbAutoSyncronize = new QCheckBox( i18n("&Automatically synchronize the terminal with the current document when possible"), this );
341 lo->addWidget( cbAutoSyncronize );
342 cbSetEditor = new QCheckBox( i18n("Set &EDITOR environment variable to 'kate -b'"), this );
343 lo->addWidget( cbSetEditor );
344 QLabel *tmp = new QLabel(this);
345 tmp->setText(i18n("Important: The document has to be closed to make the console application continue"));
346 lo->addWidget(tmp);
347 reset();
348 lo->addStretch();
349 connect( cbAutoSyncronize, SIGNAL(stateChanged(int)), SIGNAL(changed()) );
350 connect( cbSetEditor, SIGNAL(stateChanged(int)), SIGNAL(changed()) );
351}
352
353void KateKonsoleConfigPage::apply()
354{
355 KConfigGroup config(KGlobal::config(), "Konsole");
356 config.writeEntry("AutoSyncronize", cbAutoSyncronize->isChecked());
357 config.writeEntry("SetEditor", cbSetEditor->isChecked());
358 config.sync();
359 mPlugin->readConfig();
360}
361
362void KateKonsoleConfigPage::reset()
363{
364 KConfigGroup config(KGlobal::config(), "Konsole");
365 cbAutoSyncronize->setChecked(config.readEntry("AutoSyncronize", false));
366 cbSetEditor->setChecked(config.readEntry("SetEditor", false));
367}
368
369// kate: space-indent on; indent-width 2; replace-tabs on;
370
371