25 #include <QApplication>
27 #include <QtGui/QKeyEvent>
29 #include <QPrintDialog>
34 #include <KActionMenu>
35 #include <KActionCollection>
37 #include <KLocalizedString>
39 #include <KMessageBox>
42 #include <KToolInvocation>
43 #include <KStandardDirs>
44 #include <KToggleAction>
45 #include <KSelectAction>
47 #include <KXmlGuiWindow>
48 #include <KXMLGUIFactory>
49 #include <KXMLGUIBuilder>
52 #include <KStringHandler>
53 #include <KConfigGroup>
56 #include <kdeversion.h>
57 #if KDE_IS_VERSION(4, 9, 1)
58 #include <KCodecAction>
60 #include <kcodecaction.h>
81 #include <KFileDialog>
89 using namespace Konsole;
93 const KIcon SessionController::_activityIcon(
"dialog-information");
94 const KIcon SessionController::_silenceIcon(
"dialog-information");
95 const KIcon SessionController::_broadcastIcon(
"emblem-important");
98 int SessionController::_lastControllerId;
110 , _copyInputToAllTabsAction(0)
113 , _findPreviousAction(0)
114 , _urlFilterUpdateRequired(false)
115 , _searchStartLine(0)
116 , _prevSearchResultLine(0)
119 , _switchProfileMenu(0)
121 , _listenForScreenWindowUpdates(false)
122 , _preventClose(false)
123 , _keepIconUntilInteraction(false)
125 , _isSearchBarEnabled(false)
131 if (isKonsolePart()) {
132 setXMLFile(
"konsole/partui.rc");
133 setupCommonActions();
135 setXMLFile(
"konsole/sessionui.rc");
136 setupCommonActions();
140 actionCollection()->addAssociatedWidget(view);
141 foreach(
QAction * action, actionCollection()->actions()) {
146 sessionTitleChanged();
153 SLOT(sessionResizeRequest(
QSize)));
157 SLOT(showDisplayContextMenu(
QPoint)));
164 connect(_session, SIGNAL(stateChanged(
int)),
this,
165 SLOT(sessionStateChanged(
int)));
173 connect(_session, SIGNAL(changeBackgroundColorRequest(
QColor)), _view, SLOT(setBackgroundColor(
QColor)));
174 connect(_session, SIGNAL(changeForegroundColorRequest(
QColor)), _view, SLOT(setForegroundColor(
QColor)));
177 connect(_session, SIGNAL(started()),
this, SLOT(snapshot()));
180 connect(_session->emulation(), SIGNAL(outputChanged()),
this,
184 connect(_session, SIGNAL(zmodemDetected()),
this, SLOT(zmodemDownload()));
187 connect(_session, SIGNAL(flowControlEnabledChanged(
bool)), _view,
188 SLOT(setFlowControlWarningEnabled(
bool)));
189 _view->setFlowControlWarningEnabled(_session->flowControlEnabled());
196 _interactionTimer =
new QTimer(_session);
199 connect(_interactionTimer, SIGNAL(timeout()),
this, SLOT(snapshot()));
200 connect(_view, SIGNAL(keyPressedSignal(
QKeyEvent*)),
this, SLOT(interactionHandler()));
206 connect(backgroundTimer, SIGNAL(timeout()),
this, SLOT(snapshot()));
207 backgroundTimer->
start();
209 _allControllers.insert(
this);
213 _bookmarkValidProgramsToClear <<
"bash" <<
"fish" <<
"sh";
214 _bookmarkValidProgramsToClear <<
"tcsh" <<
"zsh";
220 _view->setScreenWindow(0);
222 _allControllers.remove(
this);
224 if (!_editProfileDialog.isNull()) {
225 delete _editProfileDialog.data();
228 void SessionController::trackOutput(
QKeyEvent* event)
230 Q_ASSERT(_view->screenWindow());
235 switch (event->
key()) {
237 case Qt::Key_Control:
241 _view->screenWindow()->setTrackOutput(
true);
244 void SessionController::interactionHandler()
250 _keepIconUntilInteraction =
false;
251 _interactionTimer->
start();
254 void SessionController::requireUrlFilterUpdate()
259 _urlFilterUpdateRequired =
true;
261 void SessionController::snapshot()
263 Q_ASSERT(_session != 0);
269 if (_copyToGroup && _copyToGroup->
sessions().count() > 1) {
287 return _session->currentWorkingDirectory();
292 return _session->getUrl();
303 if (!_session->isForegroundProcessActive()
304 && _bookmarkValidProgramsToClear.
contains(_session->foregroundProcessName())) {
305 _session->emulation()->sendText(
QChar(0x03));
306 _session->emulation()->sendText(
QChar(
'\n'));
310 if (url.isLocalFile()) {
311 QString path = url.toLocalFile();
312 _session->emulation()->sendText(
"cd " + KShell::quoteArg(path) +
'\r');
313 }
else if (url.protocol().isEmpty()) {
316 QString command = url.prettyUrl();
318 _session->emulation()->sendText(command +
'\r');
319 }
else if (url.protocol() ==
"ssh") {
322 if (url.port() > -1) {
323 sshCommand +=
QString(
"-p %1 ").
arg(url.port());
326 sshCommand += (url.user() +
'@');
329 sshCommand += url.host();
332 _session->sendText(sshCommand +
'\r');
334 }
else if (url.protocol() ==
"telnet") {
335 QString telnetCommand =
"telnet ";
338 telnetCommand +=
QString(
"-l %1 ").
arg(url.user());
341 telnetCommand += (url.host() +
' ');
343 if (url.port() > -1) {
347 _session->sendText(telnetCommand +
'\r');
352 KMessageBox::sorry(_view->window(),
353 i18n(
"Konsole does not know how to open the bookmark: ") +
356 kWarning() <<
"Unable to open bookmark at url" << url <<
", I do not know"
357 <<
" how to handle the protocol " << url.protocol();
363 KActionCollection* collection = actionCollection();
364 QAction* clearAction = collection->action(
"clear-history");
365 QAction* resetAction = collection->action(
"clear-history-and-reset");
366 QAction* selectAllAction = collection->action(
"select-all");
367 QAction* selectLineAction = collection->action(
"select-line");
378 _selectedText = selectedText;
379 updateCopyAction(selectedText);
382 void SessionController::updateCopyAction(
const QString& selectedText)
384 QAction* copyAction = actionCollection()->action(
"edit_copy");
390 void SessionController::updateWebSearchMenu()
393 _webSearchMenu->setVisible(
false);
394 _webSearchMenu->menu()->clear();
399 QString searchText = _selectedText;
405 KUriFilterData filterData(searchText);
406 filterData.setSearchFilteringOptions(KUriFilterData::RetrievePreferredSearchProvidersOnly);
408 if (KUriFilter::self()->filterSearchUri(filterData, KUriFilter::NormalTextFilter)) {
409 const QStringList searchProviders = filterData.preferredSearchProviders();
410 if (!searchProviders.
isEmpty()) {
411 _webSearchMenu->setText(i18n(
"Search for '%1' with", KStringHandler::rsqueeze(searchText, 16)));
415 foreach(
const QString& searchProvider, searchProviders) {
416 action =
new KAction(searchProvider, _webSearchMenu);
417 action->setIcon(KIcon(filterData.iconNameForPreferredSearchProvider(searchProvider)));
418 action->setData(filterData.queryForPreferredSearchProvider(searchProvider));
419 connect(action, SIGNAL(triggered()),
this, SLOT(handleWebShortcutAction()));
420 _webSearchMenu->addAction(action);
423 _webSearchMenu->addSeparator();
425 action =
new KAction(i18n(
"Configure Web Shortcuts..."), _webSearchMenu);
426 action->setIcon(KIcon(
"configure"));
427 connect(action, SIGNAL(triggered()),
this, SLOT(configureWebShortcuts()));
428 _webSearchMenu->addAction(action);
430 _webSearchMenu->setVisible(
true);
435 void SessionController::handleWebShortcutAction()
437 KAction* action = qobject_cast<KAction*>(
sender());
441 KUriFilterData filterData(action->data().toString());
443 if (KUriFilter::self()->filterUri(filterData,
QStringList() <<
"kurisearchfilter")) {
444 const KUrl&
url = filterData.uri();
449 void SessionController::configureWebShortcuts()
451 KToolInvocation::kdeinitExec(
"kcmshell4",
QStringList() <<
"ebrowsing");
454 void SessionController::sendSignal(
QAction* action)
456 const int signal = action->
data().
value<
int>();
457 _session->sendSignal(signal);
462 if (watched == _view) {
463 if (event->
type() == QEvent::FocusIn) {
477 if (_copyInputToAllTabsAction && _copyInputToAllTabsAction->isChecked()) {
480 copyInputToAllTabs();
489 if (event->
type() == QEvent::MouseMove &&
490 (!_viewUrlFilter || _urlFilterUpdateRequired) &&
492 if (_view->screenWindow() && !_viewUrlFilter) {
493 connect(_view->screenWindow(), SIGNAL(scrolled(
int)),
this,
494 SLOT(requireUrlFilterUpdate()));
495 connect(_view->screenWindow(), SIGNAL(outputChanged()),
this,
496 SLOT(requireUrlFilterUpdate()));
500 _view->filterChain()->addFilter(_viewUrlFilter);
503 _view->processFilters();
504 _urlFilterUpdateRequired =
false;
511 void SessionController::removeSearchFilter()
516 _view->filterChain()->removeFilter(_searchFilter);
517 delete _searchFilter;
532 connect(_searchBar, SIGNAL(unhandledMovementKeyPressed(
QKeyEvent*)),
this, SLOT(movementKeyFromSearchBarReceived(
QKeyEvent*)));
533 connect(_searchBar, SIGNAL(closeClicked()),
this, SLOT(searchClosed()));
534 connect(_searchBar, SIGNAL(searchFromClicked()),
this, SLOT(searchFrom()));
535 connect(_searchBar, SIGNAL(findNextClicked()),
this, SLOT(findNextInHistory()));
536 connect(_searchBar, SIGNAL(findPreviousClicked()),
this, SLOT(findPreviousInHistory()));
537 connect(_searchBar, SIGNAL(highlightMatchesToggled(
bool)) ,
this , SLOT(highlightMatches(
bool)));
538 connect(_searchBar, SIGNAL(matchCaseToggled(
bool)),
this, SLOT(changeSearchMatch()));
542 enableSearchBar(_isSearchBarEnabled);
552 _showMenuAction = action;
555 void SessionController::setupCommonActions()
558 KActionCollection* collection = actionCollection();
561 action = collection->addAction(
"close-session",
this, SLOT(
closeSession()));
563 action->setText(i18n(
"&Close Session"));
565 action->setText(i18n(
"&Close Tab"));
567 action->setIcon(KIcon(
"tab-close"));
568 action->setShortcut(
QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_W));
571 action = collection->addAction(
"open-browser",
this, SLOT(openBrowser()));
572 action->setText(i18n(
"Open File Manager"));
573 action->setIcon(KIcon(
"system-file-manager"));
576 action = KStandardAction::copy(
this, SLOT(copy()), collection);
577 action->setShortcut(
QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_C));
579 action->setEnabled(
false);
581 action = KStandardAction::paste(
this, SLOT(paste()), collection);
582 KShortcut pasteShortcut = action->shortcut();
583 pasteShortcut.setPrimary(
QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_V));
584 pasteShortcut.setAlternate(
QKeySequence(Qt::SHIFT + Qt::Key_Insert));
585 action->setShortcut(pasteShortcut);
587 action = collection->addAction(
"paste-selection",
this, SLOT(pasteFromX11Selection()));
588 action->setText(i18n(
"Paste Selection"));
589 action->setShortcut(
QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Insert));
591 _webSearchMenu =
new KActionMenu(i18n(
"Web Search"),
this);
592 _webSearchMenu->setIcon(KIcon(
"preferences-web-browser-shortcuts"));
593 _webSearchMenu->setVisible(
false);
594 collection->addAction(
"web-search", _webSearchMenu);
597 action = collection->addAction(
"select-all",
this, SLOT(selectAll()));
598 action->setText(i18n(
"&Select All"));
599 action->setIcon(KIcon(
"edit-select-all"));
601 action = collection->addAction(
"select-line",
this, SLOT(selectLine()));
602 action->setText(i18n(
"Select &Line"));
604 action = KStandardAction::saveAs(
this, SLOT(saveHistory()), collection);
605 action->setText(i18n(
"Save Output &As..."));
607 action = KStandardAction::print(
this, SLOT(print_screen()), collection);
608 action->setText(i18n(
"&Print Screen..."));
609 action->setShortcut(
QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_P));
611 action = collection->addAction(
"adjust-history",
this, SLOT(showHistoryOptions()));
612 action->setText(i18n(
"Adjust Scrollback..."));
613 action->setIcon(KIcon(
"configure"));
615 action = collection->addAction(
"clear-history",
this, SLOT(clearHistory()));
616 action->setText(i18n(
"Clear Scrollback"));
617 action->setIcon(KIcon(
"edit-clear-history"));
619 action = collection->addAction(
"clear-history-and-reset",
this, SLOT(clearHistoryAndReset()));
620 action->setText(i18n(
"Clear Scrollback and Reset"));
621 action->setIcon(KIcon(
"edit-clear-history"));
622 action->setShortcut(
QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_K));
625 action = collection->addAction(
"edit-current-profile",
this, SLOT(editCurrentProfile()));
626 action->setText(i18n(
"Edit Current Profile..."));
627 action->setIcon(KIcon(
"document-properties"));
629 _switchProfileMenu =
new KActionMenu(i18n(
"Switch Profile"),
this);
630 collection->addAction(
"switch-profile", _switchProfileMenu);
631 connect(_switchProfileMenu->menu(), SIGNAL(aboutToShow()),
this, SLOT(prepareSwitchProfileMenu()));
634 _findAction = KStandardAction::find(
this, SLOT(searchBarEvent()), collection);
637 _findNextAction = KStandardAction::findNext(
this, SLOT(findNextInHistory()), collection);
639 _findNextAction->setEnabled(
false);
641 _findPreviousAction = KStandardAction::findPrev(
this, SLOT(findPreviousInHistory()), collection);
643 _findPreviousAction->setEnabled(
false);
646 _codecAction =
new KCodecAction(i18n(
"Set &Encoding"),
this);
647 _codecAction->setIcon(KIcon(
"character-set"));
648 collection->addAction(
"set-encoding", _codecAction);
649 connect(_codecAction->menu(), SIGNAL(aboutToShow()),
this, SLOT(updateCodecAction()));
653 void SessionController::setupExtraActions()
656 KToggleAction* toggleAction = 0;
657 KActionCollection* collection = actionCollection();
660 action = collection->addAction(
"rename-session",
this, SLOT(renameSession()));
661 action->setText(i18n(
"&Rename Tab..."));
662 action->setIcon(KIcon(
"edit-rename"));
663 action->setShortcut(
QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_S));
666 KToggleAction* copyInputToAllTabsAction = collection->add<KToggleAction>(
"copy-input-to-all-tabs");
667 copyInputToAllTabsAction->setText(i18n(
"&All Tabs in Current Window"));
670 _copyInputToAllTabsAction = copyInputToAllTabsAction;
673 KToggleAction* copyInputToSelectedTabsAction = collection->add<KToggleAction>(
"copy-input-to-selected-tabs");
674 copyInputToSelectedTabsAction->setText(i18n(
"&Select Tabs..."));
675 copyInputToSelectedTabsAction->setShortcut(
QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Period));
679 KToggleAction* copyInputToNoneAction = collection->add<KToggleAction>(
"copy-input-to-none");
680 copyInputToNoneAction->setText(i18nc(
"@action:inmenu Do not select any tabs",
"&None"));
681 copyInputToNoneAction->setShortcut(
QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Slash));
683 copyInputToNoneAction->setChecked(
true);
687 KSelectAction* copyInputActions = collection->add<KSelectAction>(
"copy-input-to");
688 copyInputActions->setText(i18n(
"Copy Input To"));
689 copyInputActions->addAction(copyInputToAllTabsAction);
690 copyInputActions->addAction(copyInputToSelectedTabsAction);
691 copyInputActions->addAction(copyInputToNoneAction);
692 connect(copyInputActions, SIGNAL(triggered(
QAction*)),
this, SLOT(copyInputActionsTriggered(
QAction*)));
694 action = collection->addAction(
"zmodem-upload",
this, SLOT(zmodemUpload()));
695 action->setText(i18n(
"&ZModem Upload..."));
696 action->setIcon(KIcon(
"document-open"));
697 action->setShortcut(
QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_U));
700 toggleAction =
new KToggleAction(i18n(
"Monitor for &Activity"),
this);
701 toggleAction->setShortcut(
QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_A));
702 action = collection->addAction(
"monitor-activity", toggleAction);
703 connect(action, SIGNAL(toggled(
bool)),
this, SLOT(monitorActivity(
bool)));
705 toggleAction =
new KToggleAction(i18n(
"Monitor for &Silence"),
this);
706 toggleAction->setShortcut(
QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I));
707 action = collection->addAction(
"monitor-silence", toggleAction);
708 connect(action, SIGNAL(toggled(
bool)),
this, SLOT(monitorSilence(
bool)));
711 action = collection->addAction(
"enlarge-font",
this, SLOT(
increaseFontSize()));
712 action->setText(i18n(
"Enlarge Font"));
713 action->setIcon(KIcon(
"format-font-size-more"));
714 KShortcut enlargeFontShortcut = action->shortcut();
715 enlargeFontShortcut.setPrimary(
QKeySequence(Qt::CTRL + Qt::Key_Plus));
716 enlargeFontShortcut.setAlternate(
QKeySequence(Qt::CTRL + Qt::Key_Equal));
717 action->setShortcut(enlargeFontShortcut);
719 action = collection->addAction(
"shrink-font",
this, SLOT(
decreaseFontSize()));
720 action->setText(i18n(
"Shrink Font"));
721 action->setIcon(KIcon(
"format-font-size-less"));
722 action->setShortcut(KShortcut(Qt::CTRL | Qt::Key_Minus));
725 KSelectAction* sendSignalActions = collection->add<KSelectAction>(
"send-signal");
726 sendSignalActions->setText(i18n(
"Send Signal"));
729 action = collection->addAction(
"sigstop-signal");
730 action->setText(i18n(
"&Suspend Task") +
" (STOP)");
731 action->setData(SIGSTOP);
732 sendSignalActions->addAction(action);
734 action = collection->addAction(
"sigcont-signal");
735 action->setText(i18n(
"&Continue Task") +
" (CONT)");
736 action->setData(SIGCONT);
737 sendSignalActions->addAction(action);
739 action = collection->addAction(
"sighup-signal");
740 action->setText(i18n(
"&Hangup") +
" (HUP)");
741 action->setData(SIGHUP);
742 sendSignalActions->addAction(action);
744 action = collection->addAction(
"sigint-signal");
745 action->setText(i18n(
"&Interrupt Task") +
" (INT)");
746 action->setData(SIGINT);
747 sendSignalActions->addAction(action);
749 action = collection->addAction(
"sigterm-signal");
750 action->setText(i18n(
"&Terminate Task") +
" (TERM)");
751 action->setData(SIGTERM);
752 sendSignalActions->addAction(action);
754 action = collection->addAction(
"sigkill-signal");
755 action->setText(i18n(
"&Kill Task") +
" (KILL)");
756 action->setData(SIGKILL);
757 sendSignalActions->addAction(action);
759 action = collection->addAction(
"sigusr1-signal");
760 action->setText(i18n(
"User Signal &1") +
" (USR1)");
761 action->setData(SIGUSR1);
762 sendSignalActions->addAction(action);
764 action = collection->addAction(
"sigusr2-signal");
765 action->setText(i18n(
"User Signal &2") +
" (USR2)");
766 action->setData(SIGUSR2);
767 sendSignalActions->addAction(action);
769 _findAction->setShortcut(
QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_F));
771 _findPreviousAction->setShortcut(
QKeySequence(Qt::SHIFT + Qt::Key_F3));
774 void SessionController::switchProfile(
Profile::Ptr profile)
779 void SessionController::prepareSwitchProfileMenu()
781 if (_switchProfileMenu->menu()->isEmpty()) {
786 _switchProfileMenu->menu()->clear();
787 _switchProfileMenu->menu()->addActions(_profileList->
actions());
789 void SessionController::updateCodecAction()
791 _codecAction->setCurrentCodec(
QString(_session->codec()));
794 void SessionController::changeCodec(
QTextCodec* codec)
796 _session->setCodec(codec);
801 return _editProfileDialog.data();
804 void SessionController::editCurrentProfile()
816 if (!_editProfileDialog.isNull()) {
818 delete _editProfileDialog.data();
823 _editProfileDialog.data()->show();
826 void SessionController::renameSession()
832 if (_session->isRemote()) {
833 dialog->focusRemoteTabTitleText();
835 dialog->focusTabTitleText();
839 int result = dialog->exec();
844 QString tabTitle = dialog->tabTitleText();
845 QString remoteTabTitle = dialog->remoteTabTitleText();
857 if (_session->isForegroundProcessActive()) {
858 QString title = _session->foregroundProcessName();
869 question = i18n(
"A program is currently running in this session."
870 " Are you sure you want to close it?");
872 question = i18n(
"The program '%1' is currently running in this session."
873 " Are you sure you want to close it?", title);
875 int result = KMessageBox::warningYesNo(_view->window(), question, i18n(
"Confirm Close"));
876 return (result == KMessageBox::Yes) ?
true :
false;
882 if (_session->isRunning()) {
883 QString title = _session->program();
894 question = i18n(
"A program in this session would not die."
895 " Are you sure you want to kill it by force?");
897 question = i18n(
"The program '%1' is in this session would not die."
898 " Are you sure you want to kill it by force?", title);
900 int result = KMessageBox::warningYesNo(_view->window(), question, i18n(
"Confirm Close"));
901 return (result == KMessageBox::Yes) ?
true :
false;
911 if (_session->closeInNormalWay()) {
914 if (_session->closeInForceWay())
917 kWarning() <<
"Konsole failed to close a session in any way.";
926 void SessionController::openBrowser()
928 KUrl currentUrl =
url();
930 if (currentUrl.isLocalFile())
936 void SessionController::copy()
938 _view->copyToClipboard();
941 void SessionController::paste()
943 _view->pasteFromClipboard();
945 void SessionController::pasteFromX11Selection()
947 _view->pasteFromX11Selection();
949 void SessionController::selectAll()
953 _view->copyToX11Selection();
955 void SessionController::selectLine()
957 _view->selectCurrentLine();
962 while (
object != 0) {
967 object =
object->parent();
985 void SessionController::copyInputActionsTriggered(
QAction* action)
987 const int mode = action->
data().
value<
int>();
991 copyInputToAllTabs();
994 copyInputToSelectedTabs();
1004 void SessionController::copyInputToAllTabs()
1006 if (!_copyToGroup) {
1016 iterator != group.
end(); ++iterator) {
1034 void SessionController::copyInputToSelectedTabs()
1036 if (!_copyToGroup) {
1044 dialog->setMasterSession(_session);
1047 currentGroup.
remove(_session);
1049 dialog->setChosenSessions(currentGroup);
1052 int result = dialog->exec();
1056 if (result == QDialog::Accepted) {
1058 newGroup.
remove(_session);
1061 foreach(
Session * session, completeGroup) {
1074 void SessionController::copyInputToNone()
1082 iterator != group.
end(); ++iterator) {
1085 if (session != _session) {
1089 delete _copyToGroup;
1094 void SessionController::searchClosed()
1096 _isSearchBarEnabled =
false;
1097 searchHistory(
false);
1107 _searchStartLine = line;
1108 _prevSearchResultLine = line;
1111 void SessionController::listenForScreenWindowUpdates()
1113 if (_listenForScreenWindowUpdates)
1116 connect(_view->screenWindow(), SIGNAL(outputChanged()),
this,
1117 SLOT(updateSearchFilter()));
1118 connect(_view->screenWindow(), SIGNAL(scrolled(
int)),
this,
1119 SLOT(updateSearchFilter()));
1120 connect(_view->screenWindow(), SIGNAL(currentResultLineChanged()), _view,
1123 _listenForScreenWindowUpdates =
true;
1126 void SessionController::updateSearchFilter()
1128 if (_searchFilter && _searchBar) {
1129 _view->processFilters();
1133 void SessionController::searchBarEvent()
1135 QString selectedText = _view->screenWindow()->selectedText(
true,
true);
1137 _searchBar->setSearchText(selectedText);
1139 if (_searchBar->isVisible()) {
1140 _searchBar->focusLineEdit();
1142 searchHistory(
true);
1143 _isSearchBarEnabled =
true;
1147 void SessionController::enableSearchBar(
bool showSearchBar)
1152 if (showSearchBar && !_searchBar->isVisible()) {
1156 _searchBar->setVisible(showSearchBar);
1157 if (showSearchBar) {
1159 SLOT(searchTextChanged(
QString)));
1161 SLOT(findPreviousInHistory()));
1162 connect(_searchBar, SIGNAL(searchShiftPlusReturnPressed()),
this,
1163 SLOT(findNextInHistory()));
1166 SLOT(searchTextChanged(
QString)));
1168 SLOT(findPreviousInHistory()));
1169 disconnect(_searchBar, SIGNAL(searchShiftPlusReturnPressed()),
this,
1170 SLOT(findNextInHistory()));
1171 if (_view && _view->screenWindow()) {
1172 _view->screenWindow()->setCurrentResultLine(-1);
1178 bool SessionController::reverseSearchChecked()
const
1180 Q_ASSERT(_searchBar);
1182 QBitArray options = _searchBar->optionsChecked();
1186 QRegExp SessionController::regexpFromSearchBarOptions()
1188 QBitArray options = _searchBar->optionsChecked();
1193 QRegExp regExp(_searchBar->searchText(), caseHandling , syntax);
1199 void SessionController::searchHistory(
bool showSearchBar)
1201 enableSearchBar(showSearchBar);
1204 if (showSearchBar) {
1205 removeSearchFilter();
1207 listenForScreenWindowUpdates();
1210 _searchFilter->
setRegExp(regexpFromSearchBarOptions());
1211 _view->filterChain()->addFilter(_searchFilter);
1212 _view->processFilters();
1214 setFindNextPrevEnabled(
true);
1216 setFindNextPrevEnabled(
false);
1218 removeSearchFilter();
1220 _view->setFocus(Qt::ActiveWindowFocusReason);
1225 void SessionController::setFindNextPrevEnabled(
bool enabled)
1227 _findNextAction->setEnabled(enabled);
1228 _findPreviousAction->setEnabled(enabled);
1230 void SessionController::searchTextChanged(
const QString& text)
1232 Q_ASSERT(_view->screenWindow());
1234 if (_searchText == text)
1240 _view->screenWindow()->clearSelection();
1241 _view->screenWindow()->scrollTo(_searchStartLine);
1248 void SessionController::searchCompleted(
bool success)
1250 _prevSearchResultLine = _view->screenWindow()->currentResultLine();
1253 _searchBar->setFoundMatch(success);
1256 void SessionController::beginSearch(
const QString& text ,
int direction)
1258 Q_ASSERT(_searchBar);
1259 Q_ASSERT(_searchFilter);
1261 QRegExp regExp = regexpFromSearchBarOptions();
1264 if (_searchStartLine == -1) {
1268 setSearchStartTo(_view->screenWindow()->currentLine() + _view->screenWindow()->windowLines());
1273 _view->screenWindow()->setCurrentResultLine(-1);
1276 connect(task, SIGNAL(completed(
bool)),
this, SLOT(searchCompleted(
bool)));
1285 searchCompleted(
false);
1288 _view->processFilters();
1290 void SessionController::highlightMatches(
bool highlight)
1293 _view->filterChain()->addFilter(_searchFilter);
1294 _view->processFilters();
1296 _view->filterChain()->removeFilter(_searchFilter);
1302 void SessionController::searchFrom()
1304 Q_ASSERT(_searchBar);
1305 Q_ASSERT(_searchFilter);
1307 if (reverseSearchChecked()) {
1316 void SessionController::findNextInHistory()
1318 Q_ASSERT(_searchBar);
1319 Q_ASSERT(_searchFilter);
1325 void SessionController::findPreviousInHistory()
1327 Q_ASSERT(_searchBar);
1328 Q_ASSERT(_searchFilter);
1334 void SessionController::changeSearchMatch()
1336 Q_ASSERT(_searchBar);
1337 Q_ASSERT(_searchFilter);
1340 _view->screenWindow()->clearSelection();
1343 void SessionController::showHistoryOptions()
1346 const HistoryType& currentHistory = _session->historyType();
1360 int result = dialog->exec();
1365 scrollBackOptionsChanged(dialog->mode(), dialog->lineCount());
1368 void SessionController::sessionResizeRequest(
const QSize& size)
1373 void SessionController::scrollBackOptionsChanged(
int mode,
int lines)
1388 void SessionController::print_screen()
1396 dialog->setWindowTitle(i18n(
"Print Shell"));
1397 connect(dialog, SIGNAL(accepted()), options, SLOT(saveSettings()));
1398 if (dialog->exec() != QDialog::Accepted)
1402 painter.
begin(&printer);
1404 KConfigGroup configGroup(KGlobal::config(),
"PrintOptions");
1406 if (configGroup.readEntry(
"ScaleOutput",
true)) {
1407 double scale = qMin(printer.
pageRect().
width() /
static_cast<double>(_view->width()),
1408 printer.
pageRect().
height() /
static_cast<double>(_view->height()));
1409 painter.
scale(scale, scale);
1412 _view->printContent(painter, configGroup.readEntry(
"PrinterFriendly",
true));
1415 void SessionController::saveHistory()
1423 void SessionController::clearHistory()
1425 _session->clearHistory();
1426 _view->updateImage();
1429 void SessionController::clearHistoryAndReset()
1434 Emulation* emulation = _session->emulation();
1436 _session->refresh();
1443 _view->increaseFontSize();
1448 _view->decreaseFontSize();
1451 void SessionController::monitorActivity(
bool monitor)
1453 _session->setMonitorActivity(monitor);
1455 void SessionController::monitorSilence(
bool monitor)
1457 _session->setMonitorSilence(monitor);
1459 void SessionController::updateSessionIcon()
1462 if (_copyToGroup && _copyToGroup->
sessions().count() > 1) {
1466 if (!_keepIconUntilInteraction) {
1472 void SessionController::sessionTitleChanged()
1474 if (_sessionIconName != _session->iconName()) {
1475 _sessionIconName = _session->iconName();
1476 _sessionIcon = KIcon(_sessionIconName);
1477 updateSessionIcon();
1484 title.
replace(
"%w", _session->userTitle());
1496 void SessionController::showDisplayContextMenu(
const QPoint& position)
1501 if (!clientBuilder()) {
1502 setClientBuilder(
new KXMLGUIBuilder(_view));
1505 KXMLGUIFactory* factory =
new KXMLGUIFactory(clientBuilder(),
this);
1506 factory->addClient(
this);
1510 QPointer<QMenu> popup = qobject_cast<
QMenu*>(factory()->container(
"session-popup-menu",
this));
1516 contentActions << contentSeparator;
1517 popup->insertActions(popup->actions().value(0, 0), contentActions);
1522 updateWebSearchMenu();
1524 _preventClose =
true;
1526 if (_showMenuAction) {
1528 popup->removeAction( _showMenuAction);
1530 popup->insertAction(_switchProfileMenu, _showMenuAction);
1534 QAction* chosen = popup->exec(_view->mapToGlobal(position));
1543 foreach(
QAction * action, contentActions) {
1544 popup->removeAction(action);
1547 delete contentSeparator;
1550 _preventClose =
false;
1552 if (chosen && chosen->
objectName() ==
"close-session")
1555 kWarning() <<
"Unable to display popup menu for session"
1557 <<
", no GUI factory available to build the popup.";
1561 void SessionController::movementKeyFromSearchBarReceived(
QKeyEvent *event)
1567 void SessionController::sessionStateChanged(
int state)
1569 if (state == _previousState)
1574 _keepIconUntilInteraction =
true;
1577 _keepIconUntilInteraction =
true;
1579 if (_sessionIconName != _session->iconName()) {
1580 _sessionIconName = _session->iconName();
1581 _sessionIcon = KIcon(_sessionIconName);
1584 updateSessionIcon();
1587 _previousState = state;
1590 void SessionController::zmodemDownload()
1592 QString zmodem = KStandardDirs::findExe(
"rz");
1594 zmodem = KStandardDirs::findExe(
"lrz");
1597 const QString path = KFileDialog::getExistingDirectory(
1599 i18n(
"Save ZModem Download to..."));
1602 _session->startZModem(zmodem, path,
QStringList());
1606 KMessageBox::error(_view,
1607 i18n(
"<p>A ZModem file transfer attempt has been detected, "
1608 "but no suitable ZModem software was found on this system.</p>"
1609 "<p>You may wish to install the 'rzsz' or 'lrzsz' package.</p>"));
1611 _session->cancelZModem();
1615 void SessionController::zmodemUpload()
1617 if (_session->isZModemBusy()) {
1618 KMessageBox::sorry(_view,
1619 i18n(
"<p>The current session already has a ZModem file transfer in progress.</p>"));
1622 QString zmodem = KStandardDirs::findExe(
"sz");
1624 zmodem = KStandardDirs::findExe(
"lsz");
1627 KMessageBox::sorry(_view,
1628 i18n(
"<p>No suitable ZModem software was found on this system.</p>"
1629 "<p>You may wish to install the 'rzsz' or 'lrzsz' package.</p>"));
1634 i18n(
"Select Files for ZModem Upload"));
1636 _session->startZModem(zmodem,
QString(), files);
1640 bool SessionController::isKonsolePart()
const
1643 if (
QString(qApp->metaObject()->className()) ==
"Konsole::Application")
1651 , _autoDelete(false)
1656 _autoDelete = enable;
1664 _sessions << session;
1687 KFileDialog* dialog =
new KFileDialog(
QString(
":konsole") ,
1689 dialog->setOperationMode(KFileDialog::Saving);
1690 dialog->setConfirmOverwrite(
true);
1693 mimeTypes <<
"text/plain";
1694 mimeTypes <<
"text/html";
1695 dialog->setMimeFilter(mimeTypes,
"text/plain");
1701 dialog->setCaption(i18n(
"Save Output From %1", session->title(
Session::NameRole)));
1703 int result = dialog->exec();
1705 if (result != QDialog::Accepted)
1708 KUrl url = dialog->selectedUrl();
1710 if (!url.isValid()) {
1712 KMessageBox::sorry(0 , i18n(
"%1 is an invalid URL, the output could not be saved.", url.url()));
1716 KIO::TransferJob* job = KIO::put(url,
1722 KIO::Overwrite | (url.isLocalFile() ? KIO::HideProgressInfo : KIO::DefaultFlags)
1731 jobInfo.session = session;
1732 jobInfo.lastLineFetched = -1;
1738 if (dialog->currentMimeFilter() ==
"text/html")
1743 _jobSession.
insert(job, jobInfo);
1746 this, SLOT(jobDataRequested(KIO::Job*,
QByteArray&)));
1747 connect(job, SIGNAL(result(KJob*)),
1748 this, SLOT(jobResult(KJob*)));
1751 dialog->deleteLater();
1753 void SaveHistoryTask::jobDataRequested(KIO::Job* job ,
QByteArray& data)
1758 const int LINES_PER_REQUEST = 500;
1760 SaveJob& info = _jobSession[job];
1768 int sessionLines = info.session->emulation()->lineCount();
1770 if (sessionLines - 1 == info.lastLineFetched)
1773 int copyUpToLine = qMin(info.lastLineFetched + LINES_PER_REQUEST ,
1777 info.decoder->begin(&stream);
1778 info.session->emulation()->writeToStream(info.decoder , info.lastLineFetched + 1 , copyUpToLine);
1779 info.decoder->end();
1781 info.lastLineFetched = copyUpToLine;
1784 void SaveHistoryTask::jobResult(KJob* job)
1787 KMessageBox::sorry(0 , i18n(
"A problem occurred when saving the output.\n%1", job->errorString()));
1804 _windows.insert(session, searchWindow);
1812 executeOnScreenWindow(iter.
key() , iter.
value());
1816 void SearchHistoryTask::executeOnScreenWindow(
SessionPtr session , ScreenWindowPtr window)
1821 Emulation* emulation = session->emulation();
1826 const int lastLine = window->lineCount() - 1;
1829 if (forwards && (_startLine == lastLine)) {
1831 }
else if (!forwards && (_startLine == 0)) {
1832 startLine = lastLine;
1834 startLine = _startLine + (forwards ? 1 : -1);
1846 int line = startLine;
1852 const int maxDelta = qMin(window->lineCount(), 10000);
1853 int delta = forwards ? maxDelta : -maxDelta;
1856 bool hasWrapped =
false;
1868 if (endLine == lastLine)
1870 else if (endLine == 0)
1876 endLine = qMin(startLine , endLine);
1878 endLine = qMax(startLine , endLine);
1882 if (endLine > lastLine) {
1885 }
else if (endLine < 0) {
1891 decoder.
begin(&searchStream);
1892 emulation->
writeToStream(&decoder, qMin(endLine, line) , qMax(endLine, line));
1896 string.append(
'\n');
1899 pos =
string.indexOf(_regExp);
1901 pos =
string.lastIndexOf(_regExp);
1907 while (newLines < linePositions.
count() && linePositions[newLines] <= pos)
1913 int findPos = qMin(line, endLine) + newLines;
1915 highlightResult(window, findPos);
1925 }
while (startLine != endLine);
1928 window->clearSelection();
1929 window->notifyOutputChanged();
1934 void SearchHistoryTask::highlightResult(ScreenWindowPtr window ,
int findPos)
1942 if ((findPos < window->currentLine()) ||
1943 (findPos >= (window->currentLine() + window->windowLines()))) {
1944 int centeredScrollPos = findPos - window->windowLines() / 2;
1945 if (centeredScrollPos < 0) {
1946 centeredScrollPos = 0;
1949 window->scrollTo(centeredScrollPos);
1952 window->setTrackOutput(
false);
1953 window->notifyOutputChanged();
1954 window->setCurrentResultLine(findPos);
1959 , _direction(BackwardsSearch)
1965 _direction = direction;
1977 _regExp = expression;
1987 return _session->userTitle();
1993 #include "SessionController.moc"
A terminal character decoder which produces pretty HTML markup.
void setInterval(int msec)
SaveHistoryTask(QObject *parent=0)
Constructs a new task to save session output to URLs.
SessionTask(QObject *parent=0)
virtual void end()
End decoding.
static SessionManager * instance()
Returns the session manager instance.
void setRecordLinePositions(bool record)
Enables recording of character positions at which new lines are added.
Represents a terminal session consisting of a pseudo-teletype and a terminal emulation.
Provides the menu actions to manipulate a single terminal session and view pair.
QString title() const
Returns the title associated with a view.
QString & append(QChar ch)
void setShortcutContext(Qt::ShortcutContext context)
void setSessionProfile(Session *session, Profile::Ptr profile)
Sets the profile associated with a session.
iterator insert(const Key &key, const T &value)
Searches are case-sensitive or not.
void setStartLine(int startLine)
The line from which the search will be done.
Searches backwards through the output, starting at the current selection.
QList< QAction * > actions()
Returns a list of actions representing profiles.
virtual bool isEnabled() const =0
Returns true if the history is enabled ( can store lines of output ) or false otherwise.
Searches use regular expressions.
void setSeparator(bool b)
void setShowMenuAction(QAction *action)
Sets the action displayed in the session's context menu to hide or show the menu bar.
virtual KUrl url() const
Returns the URL current associated with a view.
QRegExp regExp() const
Returns the regular expression which is searched for when execute() is called.
void setIdentifier(int id)
Subclasses may call this method to change the identifier.
Abstract class representing a task which can be performed on a group of sessions. ...
virtual int maximumLineCount() const =0
Returns the maximum number of lines which this history type can store or -1 if the history can store ...
void scale(qreal sx, qreal sy)
static const KXmlGuiWindow * findWindow(const QObject *object)
SessionController(Session *session, TerminalDisplay *view, QObject *parent)
Constructs a new SessionController which operates on session and view.
bool contains(const QString &str, Qt::CaseSensitivity cs) const
ProfileList provides a list of actions which represent session profiles that a SessionManager can cre...
QList< Session * > sessions() const
Returns the list of sessions currently in the group.
QString simplified() const
The title of the session which is displayed in tabs etc.
void setTitle(const QString &title)
Subclasses may call this method to change the title.
virtual void execute()=0
Executes the task on each of the sessions in the group.
void setIcon(const QIcon &icon)
Subclasses may call this method to change the icon.
SearchDirection searchDirection() const
Returns the current search direction.
void titleChanged(ViewProperties *properties)
Emitted when the title for a view changes.
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
virtual ~SaveHistoryTask()
QList< TerminalDisplay * > views() const
Returns the views connected to this session.
virtual void reset()=0
Resets the state of the terminal.
Profile::Ptr sessionProfile(Session *session) const
Returns the profile associated with a session.
static bool hasTerminalDisplayInSameWindow(const Session *session, const KXmlGuiWindow *window)
virtual void writeToStream(TerminalCharacterDecoder *decoder, int startLine, int endLine)
Copies the output history from startLine to endLine into stream, using decoder to convert the termina...
void setSelectionByLineRange(int start, int end)
Sets the selection as the range specified by line start and line end in the whole history...
A dialog which allows the user to edit a profile.
virtual void rename()
Requests the renaming of this view.
virtual bool event(QEvent *e)
A terminal character decoder which produces plain text, ignoring colors and other appearance-related ...
void increaseFontSize()
Increase font size.
void focused(SessionController *controller)
Emitted when the view associated with the controller is focused.
The emulation is currently receiving data from its terminal input.
EditProfileDialog * profileDialogPointer()
const char * name() const
Do not copy keyboard input to other tabs.
QString number(int n, int base)
int count(const T &value) const
void setSearchDirection(SearchDirection direction)
Specifies the direction to search in when execute() is called.
void processEvents(QFlags< QEventLoop::ProcessEventsFlag > flags)
Base class for terminal character decoders.
void setSearchStartToWindowCurrentLine()
set start line to the first or last line (depending on the reverse search setting) in the terminal di...
QList< SessionPtr > sessions() const
Returns a list of sessions in the group.
void installEventFilter(QObject *filterObj)
Provides a group of sessions which is divided into master and slave sessions.
void selectionChanged(const QString &selectedText)
update actions which are closely related with the selected text.
virtual bool confirmForceClose() const
void addScreenWindow(Session *session, ScreenWindow *searchWindow)
Adds a screen window to the list to search when execute() is called.
void addSession(Session *session)
Adds a new session to the group.
Provides a window onto a section of a terminal screen.
Searches forwards through the output, starting at the current selection.
void setMasterStatus(Session *session, bool master)
Sets whether a particular session is a master within the group.
bool sendEvent(QObject *receiver, QEvent *event)
SearchHistoryTask(QObject *parent=0)
Constructs a new search task.
void fireActivity()
Emits the activity() signal.
Base class for terminal emulation back-ends.
The emulation is currently receiving user input.
QPointer< Session > session()
Returns the session associated with this controller.
void setSearchStartTo(int line)
Set the start line from which the next search will be done.
Tab title format used session currently contains a connection to a remote computer (via SSH) ...
void setupPrimaryScreenSpecificActions(bool use)
update actions which are meaningful only when primary screen is in use.
int remove(const Key &key)
A task which searches through the output of sessions for matches for a given regular expression...
void setSessionController(SessionController *controller)
virtual void execute()
Performs a search through the session's history, starting at the position of the current selection...
virtual bool eventFilter(QObject *watched, QEvent *event)
Encapsulates user-visible information about the terminal session currently being displayed in a view...
void setMasterMode(int mode)
Specifies which activity in the group's master sessions is propagated to all sessions in the group...
void removeSession(Session *session)
Removes a session from the group.
A widget which allows users to search incrementally through a document for a a text string or regular...
void setRegExp(const QRegExp &text)
Sets the regular expression which the filter searches for in blocks of text.
A filter which searches for sections of text matching a regular expression and creates a new RegExpFi...
Copy keyboard input to all the other tabs in current window.
QList< int > linePositions() const
Returns of character positions in the output stream at which new lines where added.
bool contains(const T &value) const
const Profile::Ptr lookupProfile() const
KSharedPtr< Profile > Ptr
QString & replace(int position, int n, QChar after)
virtual void begin(QTextStream *output)
Begin decoding characters.
void openUrl(const KUrl &url)
Issues a command to the session to navigate to the specified URL.
bool remove(const T &value)
void setSearchBar(IncrementalSearchBar *searchBar)
Sets the widget used for searches through the session's output.
Default tab title format.
A filter which matches URLs in blocks of text.
virtual void execute()
Opens a save file dialog for each session in the group and begins saving each session's history to th...
void closeSession()
close the associated session.
SearchDirection
This enum describes the strategies available for searching through the session's output.
Search from the bottom and up.
All output is remembered for the duration of the session.
void addSession(Session *session)
Adds a session to the group.
QTextCodec * codecForName(const QByteArray &name)
QSet< T > fromList(const QList< T > &list)
A fixed number of lines of output are remembered.
bool isUnlimited() const
Returns true if the history size is unlimited.
QString userTitle() const
Returns the "window title" of the associated session.
QString section(QChar sep, int start, int end, QFlags< QString::SectionFlag > flags) const
Copy keyboard input to user selected tabs in current window.
Any input key presses in the master sessions are sent to all sessions in the group.
A task which prompts for a URL for each session and saves that session's output to the given URL...
void setRegExp(const QRegExp ®Exp)
Sets the regular expression which is searched for when execute() is called.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
IncrementalSearchBar * searchBar() const
see setSearchBar()
bool begin(QPaintDevice *device)
A widget which displays output from a terminal emulation and sends input keypresses and mouse activit...
void setAutoDelete(bool enable)
Sets whether the task automatically deletes itself when the task has been finished.
bool autoDelete() const
Returns true if the task automatically deletes itself.
virtual bool confirmClose() const
Sub-classes may re-implement this method to display a message to the user to allow them to confirm wh...
void completed(bool success)
Emitted when the task has completed.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
void decreaseFontSize()
Decrease font size.
virtual QString currentDir() const
Returns the current directory associated with a view.
void currentDirectoryChanged(const QString &dir)
Emitted when the current working directory of the session associated with the controller is changed...
void setSingleShot(bool singleShot)