Files
konsole/src/SessionController.h
2011-09-13 18:39:02 -09:00

467 lines
14 KiB
C++

/*
Copyright 2006-2008 by Robert Knight <robertknight@gmail.com>
Copyright 2009 by Thomas Dreibholz <dreibh@iem.uni-due.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
*/
#ifndef SESSIONCONTROLLER_H
#define SESSIONCONTROLLER_H
// Qt
#include <QtGui/QIcon>
#include <QtCore/QList>
#include <QtCore/QSet>
#include <QtCore/QPointer>
#include <QtCore/QString>
#include <QtCore/QThread>
#include <QtCore/QHash>
// KDE
#include <KActionCollection>
#include <KActionMenu>
#include <KIcon>
#include <KXMLGUIClient>
// Konsole
#include "HistorySizeDialog.h"
#include "ViewProperties.h"
#include "Profile.h"
namespace KIO
{
class Job;
}
class QAction;
class QTextCodec;
class KCodecAction;
class KUrl;
class KJob;
namespace Konsole
{
class Session;
class SessionGroup;
class ScreenWindow;
class TerminalDisplay;
class IncrementalSearchBar;
class ProfileList;
class UrlFilter;
class RegExpFilter;
// SaveHistoryTask
class TerminalCharacterDecoder;
typedef QPointer<Session> SessionPtr;
/**
* Provides the menu actions to manipulate a single terminal session and view pair.
* The actions provided by this class are defined in the sessionui.rc XML file.
*
* SessionController monitors the session and provides access to basic information
* about the session such as title(), icon() and currentDir(). SessionController
* provides notifications of activity in the session via the activity() signal.
*
* When the controlled view receives the focus, the focused() signal is emitted
* with a pointer to the controller. This can be used by main application window
* which contains the view to plug the controller's actions into the menu when
* the view is focused.
*/
class KONSOLEPRIVATE_EXPORT SessionController : public ViewProperties , public KXMLGUIClient
{
Q_OBJECT
public:
/**
* Constructs a new SessionController which operates on @p session and @p view.
*/
SessionController(Session* session , TerminalDisplay* view, QObject* parent);
~SessionController();
/** Returns the session associated with this controller */
QPointer<Session> session() { return _session; }
/** Returns the view associated with this controller */
QPointer<TerminalDisplay> view() { return _view; }
/**
* Returns true if the controller is valid.
* A valid controller is one which has a non-null session() and view().
*
* Equivalent to "!session().isNull() && !view().isNull()"
*/
bool isValid() const;
/**
* Sets the widget used for searches through the session's output.
*
* When the user clicks on the "Search Output" menu action the @p searchBar 's
* show() method will be called. The SessionController will then connect to the search
* bar's signals to update the search when the widget's controls are pressed.
*/
void setSearchBar( IncrementalSearchBar* searchBar );
/**
* see setSearchBar()
*/
IncrementalSearchBar* searchBar() const;
/**
* Sets the action displayed in the session's context menu to hide or
* show the menu bar.
*/
void setShowMenuAction(QAction* action);
// reimplemented
virtual KUrl url() const;
virtual QString currentDir() const;
virtual void rename();
virtual bool confirmClose() const;
// Reimplemented to watch for events happening to the view
virtual bool eventFilter(QObject* watched , QEvent* event);
/** Returns the set of all controllers that exist. */
static QSet<SessionController*> allControllers()
{ return _allControllers; }
signals:
/**
* Emitted when the view associated with the controller is focused.
* This can be used by other classes to plug the controller's actions into a window's
* menus.
*/
void focused( SessionController* controller );
public slots:
/**
* Issues a command to the session to navigate to the specified URL.
* This may not succeed if the foreground program does not understand
* the command sent to it ( 'cd path' for local URLs ) or is not
* responding to input.
*
* openUrl() currently supports urls for local paths and those
* using the 'ssh' protocol ( eg. "ssh://joebloggs@hostname" )
*/
void openUrl( const KUrl& url );
/**
* update actions which are meaningful only when rimary screen is in use.
*/
void setupPrimaryScreenSpecificActions( bool use);
/**
* enable or disable the copy action
*/
void updateCopyAction( const QString & text );
private slots:
// menu item handlers
void openBrowser();
void copy();
void paste();
void pasteSelection(); // shortcut only
void copyInputToAllTabs();
void copyInputToSelectedTabs();
void copyInputToNone();
void editCurrentProfile();
void changeCodec(QTextCodec* codec);
void searchHistory(bool showSearchBar);
void findNextInHistory();
void findPreviousInHistory();
void changeSearchMatch();
void saveHistory();
void showHistoryOptions();
void clearHistory();
void clearHistoryAndReset();
void closeSession();
void monitorActivity(bool monitor);
void monitorSilence(bool monitor);
void increaseTextSize();
void decreaseTextSize();
void renameSession();
void saveSession();
void changeProfile(Profile::Ptr profile);
// other
void prepareChangeProfileMenu();
void updateCodecAction();
void showDisplayContextMenu(const QPoint& position);
void sessionStateChanged(int state);
void sessionTitleChanged();
void searchTextChanged(const QString& text);
void searchCompleted(bool success);
void searchClosed(); // called when the user clicks on the
// history search bar's close button
void snapshot(); // called periodically as the user types
// to take a snapshot of the state of the
// foreground process in the terminal
void requireUrlFilterUpdate();
void highlightMatches(bool highlight);
void scrollBackOptionsChanged(int mode , int lines, bool saveToCurrentProfile);
void sessionResizeRequest(const QSize& size);
void trackOutput(QKeyEvent* event); // move view to end of current output
// when a key press occurs in the
// display area
void updateSearchFilter();
void zmodemDownload();
void zmodemUpload();
/* Returns true if called within a KPart; false if called within Konsole. */
bool isKonsolePart() const;
private:
// begins the search
// text - pattern to search for
// direction - value from SearchHistoryTask::SearchDirection enum to specify
// the search direction
void beginSearch(const QString& text , int direction);
void setupActions();
void removeSearchFilter(); // remove and delete the current search filter if set
void setFindNextPrevEnabled(bool enabled);
void listenForScreenWindowUpdates();
private:
void updateSessionIcon();
QPointer<Session> _session;
QPointer<TerminalDisplay> _view;
SessionGroup* _copyToGroup;
ProfileList* _profileList;
KIcon _sessionIcon;
QString _sessionIconName;
int _previousState;
UrlFilter* _viewUrlFilter;
RegExpFilter* _searchFilter;
KAction* _copyToAllTabsAction;
KAction* _copyToSelectedAction;
KAction* _copyToNoneAction;
KAction* _searchToggleAction;
KAction* _findNextAction;
KAction* _findPreviousAction;
bool _urlFilterUpdateRequired;
QPointer<IncrementalSearchBar> _searchBar;
KCodecAction* _codecAction;
KActionMenu* _changeProfileMenu;
bool _listenForScreenWindowUpdates;
bool _preventClose;
static QSet<SessionController*> _allControllers;
static int _lastControllerId;
static KIcon _activityIcon;
static KIcon _silenceIcon;
};
inline bool SessionController::isValid() const
{
return !_session.isNull() && !_view.isNull();
}
/**
* Abstract class representing a task which can be performed on a group of sessions.
*
* Create a new instance of the appropriate sub-class for the task you want to perform and
* call the addSession() method to add each session which needs to be processed.
*
* Finally, call the execute() method to perform the sub-class specific action on each
* of the sessions.
*/
class SessionTask : public QObject
{
Q_OBJECT
public:
SessionTask(QObject* parent = 0);
/**
* Sets whether the task automatically deletes itself when the task has been finished.
* Depending on whether the task operates synchronously or asynchronously, the deletion
* may be scheduled immediately after execute() returns or it may happen some time later.
*/
void setAutoDelete(bool enable);
/** Returns true if the task automatically deletes itself. See setAutoDelete() */
bool autoDelete() const;
/** Adds a new session to the group */
void addSession(Session* session);
/**
* Executes the task on each of the sessions in the group.
* The completed() signal is emitted when the task is finished, depending on the specific sub-class
* execute() may be synchronous or asynchronous
*/
virtual void execute() = 0;
signals:
/**
* Emitted when the task has completed.
* Depending on the task this may occur just before execute() returns, or it
* may occur later
*
* @param success Indicates whether the task completed successfully or not
*/
void completed(bool success);
protected:
/** Returns a list of sessions in the group */
QList< SessionPtr > sessions() const;
private:
bool _autoDelete;
QList< SessionPtr > _sessions;
};
/**
* A task which prompts for a URL for each session and saves that session's output
* to the given URL
*/
class SaveHistoryTask : public SessionTask
{
Q_OBJECT
public:
/** Constructs a new task to save session output to URLs */
SaveHistoryTask(QObject* parent = 0);
virtual ~SaveHistoryTask();
/**
* Opens a save file dialog for each session in the group and begins saving
* each session's history to the given URL.
*
* The data transfer is performed asynchronously and will continue after execute() returns.
*/
virtual void execute();
private slots:
void jobDataRequested(KIO::Job* job , QByteArray& data);
void jobResult(KJob* job);
private:
class SaveJob // structure to keep information needed to process
// incoming data requests from jobs
{
public:
SessionPtr session; // the session associated with a history save job
int lastLineFetched; // the last line processed in the previous data request
// set this to -1 at the start of the save job
TerminalCharacterDecoder* decoder; // decoder used to convert terminal characters
// into output
};
QHash<KJob*,SaveJob> _jobSession;
};
class SearchHistoryThread;
/**
* A task which searches through the output of sessions for matches for a given regular expression.
* SearchHistoryTask operates on ScreenWindow instances rather than sessions added by addSession().
* A screen window can be added to the list to search using addScreenWindow()
*
* When execute() is called, the search begins in the direction specified by searchDirection(),
* starting at the position of the current selection.
*
* FIXME - This is not a proper implementation of SessionTask, in that it ignores sessions specified
* with addSession()
*
* TODO - Implementation requirements:
* May provide progress feedback to the user when searching very large output logs.
*/
class SearchHistoryTask : public SessionTask
{
Q_OBJECT
public:
/**
* This enum describes the strategies available for searching through the
* session's output.
*/
enum SearchDirection
{
/** Searches forwards through the output, starting at the current selection. */
ForwardsSearch,
/** Searches backwars through the output, starting at the current selection. */
BackwardsSearch
};
/**
* Constructs a new search task.
*/
explicit SearchHistoryTask(QObject* parent = 0);
/** Adds a screen window to the list to search when execute() is called. */
void addScreenWindow( Session* session , ScreenWindow* searchWindow);
/** Sets the regular expression which is searched for when execute() is called */
void setRegExp(const QRegExp& regExp);
/** Returns the regular expression which is searched for when execute() is called */
QRegExp regExp() const;
/** Specifies the direction to search in when execute() is called. */
void setSearchDirection( SearchDirection direction );
/** Returns the current search direction. See setSearchDirection(). */
SearchDirection searchDirection() const;
/**
* Performs a search through the session's history, starting at the position
* of the current selection, in the direction specified by setSearchDirection().
*
* If it finds a match, the ScreenWindow specified in the constructor is
* scrolled to the position where the match occurred and the selection
* is set to the matching text. execute() then returns immediately.
*
* To continue the search looking for further matches, call execute() again.
*/
virtual void execute();
private:
typedef QPointer<ScreenWindow> ScreenWindowPtr;
void executeOnScreenWindow( SessionPtr session , ScreenWindowPtr window );
void highlightResult( ScreenWindowPtr window , int position);
QMap< SessionPtr , ScreenWindowPtr > _windows;
QRegExp _regExp;
SearchDirection _direction;
static QPointer<SearchHistoryThread> _thread;
};
}
#endif //SESSIONCONTROLLER_H