File indexing completed on 2018-01-16 12:10:22

0001 /*
0002     Copyright 2006-2008 by Robert Knight <robertknight@gmail.com>
0003     Copyright 2009 by Thomas Dreibholz <dreibh@iem.uni-due.de>
0004 
0005     This program is free software; you can redistribute it and/or modify
0006     it under the terms of the GNU General Public License as published by
0007     the Free Software Foundation; either version 2 of the License, or
0008     (at your option) any later version.
0009 
0010     This program is distributed in the hope that it will be useful,
0011     but WITHOUT ANY WARRANTY; without even the implied warranty of
0012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013     GNU General Public License for more details.
0014 
0015     You should have received a copy of the GNU General Public License
0016     along with this program; if not, write to the Free Software
0017     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0018     02110-1301  USA.
0019 */
0020 
0021 #ifndef SESSIONCONTROLLER_H
0022 #define SESSIONCONTROLLER_H
0023 
0024 // Qt
0025 #include <QList>
0026 #include <QSet>
0027 #include <QPointer>
0028 #include <QString>
0029 #include <QHash>
0030 #include <QRegularExpression>
0031 
0032 // KDE
0033 #include <KXMLGUIClient>
0034 
0035 // Konsole
0036 #include "ViewProperties.h"
0037 #include "Profile.h"
0038 #include "Enumeration.h"
0039 
0040 namespace KIO {
0041 class Job;
0042 }
0043 
0044 class QAction;
0045 class QTextCodec;
0046 class QKeyEvent;
0047 class QTimer;
0048 class QUrl;
0049 
0050 class KCodecAction;
0051 class KJob;
0052 class QAction;
0053 class KActionMenu;
0054 
0055 namespace Konsole {
0056 class Session;
0057 class SessionGroup;
0058 class ScreenWindow;
0059 class TerminalDisplay;
0060 class IncrementalSearchBar;
0061 class ProfileList;
0062 class RegExpFilter;
0063 class UrlFilter;
0064 class FileFilter;
0065 class EditProfileDialog;
0066 
0067 // SaveHistoryTask
0068 class TerminalCharacterDecoder;
0069 
0070 typedef QPointer<Session> SessionPtr;
0071 
0072 /**
0073  * Provides the menu actions to manipulate a single terminal session and view pair.
0074  * The actions provided by this class are defined in the sessionui.rc XML file.
0075  *
0076  * SessionController monitors the session and provides access to basic information
0077  * about the session such as title(), icon() and currentDir().  SessionController
0078  * provides notifications of activity in the session via the activity() signal.
0079  *
0080  * When the controlled view receives the focus, the focused() signal is emitted
0081  * with a pointer to the controller.  This can be used by main application window
0082  * which contains the view to plug the controller's actions into the menu when
0083  * the view is focused.
0084  */
0085 class KONSOLEPRIVATE_EXPORT SessionController : public ViewProperties, public KXMLGUIClient
0086 {
0087     Q_OBJECT
0088 
0089 public:
0090     enum CopyInputToEnum {
0091         /** Copy keyboard input to all the other tabs in current window */
0092         CopyInputToAllTabsMode = 0,
0093 
0094         /** Copy keyboard input to user selected tabs in current window */
0095         CopyInputToSelectedTabsMode = 1,
0096 
0097         /** Do not copy keyboard input to other tabs */
0098         CopyInputToNoneMode = 2
0099     };
0100 
0101     /**
0102      * Constructs a new SessionController which operates on @p session and @p view.
0103      */
0104     SessionController(Session *session, TerminalDisplay *view, QObject *parent);
0105     ~SessionController() Q_DECL_OVERRIDE;
0106 
0107     /** Returns the session associated with this controller */
0108     QPointer<Session> session()
0109     {
0110         return _session;
0111     }
0112 
0113     /** Returns the view associated with this controller */
0114     QPointer<TerminalDisplay> view()
0115     {
0116         return _view;
0117     }
0118 
0119     /**
0120      * Returns the "window title" of the associated session.
0121      */
0122     QString userTitle() const;
0123 
0124     /**
0125      * Returns true if the controller is valid.
0126      * A valid controller is one which has a non-null session() and view().
0127      *
0128      * Equivalent to "!session().isNull() && !view().isNull()"
0129      */
0130     bool isValid() const;
0131 
0132     /** Set the start line from which the next search will be done **/
0133     void setSearchStartTo(int line);
0134 
0135     /** set start line to the first or last line (depending on the reverse search
0136      * setting) in the terminal display **/
0137     void setSearchStartToWindowCurrentLine();
0138 
0139     /**
0140      * Sets the widget used for searches through the session's output.
0141      *
0142      * When the user clicks on the "Search Output" menu action the @p searchBar 's
0143      * show() method will be called.  The SessionController will then connect to the search
0144      * bar's signals to update the search when the widget's controls are pressed.
0145      */
0146     void setSearchBar(IncrementalSearchBar *searchBar);
0147     /**
0148      * see setSearchBar()
0149      */
0150     IncrementalSearchBar *searchBar() const;
0151 
0152     /**
0153      * Sets the action displayed in the session's context menu to hide or
0154      * show the menu bar.
0155      */
0156     void setShowMenuAction(QAction *action);
0157 
0158     EditProfileDialog *profileDialogPointer();
0159 
0160     // reimplemented
0161     QUrl url() const Q_DECL_OVERRIDE;
0162     QString currentDir() const Q_DECL_OVERRIDE;
0163     void rename() Q_DECL_OVERRIDE;
0164     bool confirmClose() const Q_DECL_OVERRIDE;
0165     virtual bool confirmForceClose() const;
0166 
0167     // Reimplemented to watch for events happening to the view
0168     bool eventFilter(QObject *watched, QEvent *event) Q_DECL_OVERRIDE;
0169 
0170     /** Returns the set of all controllers that exist. */
0171     static QSet<SessionController *> allControllers()
0172     {
0173         return _allControllers;
0174     }
0175 
0176 Q_SIGNALS:
0177     /**
0178      * Emitted when the view associated with the controller is focused.
0179      * This can be used by other classes to plug the controller's actions into a window's
0180      * menus.
0181      */
0182     void focused(SessionController *controller);
0183 
0184     void rawTitleChanged();
0185 
0186     /**
0187      * Emitted when the current working directory of the session associated with
0188      * the controller is changed.
0189      */
0190     void currentDirectoryChanged(const QString &dir);
0191 
0192 public Q_SLOTS:
0193     /**
0194      * Issues a command to the session to navigate to the specified URL.
0195      * This may not succeed if the foreground program does not understand
0196      * the command sent to it ( 'cd path' for local URLs ) or is not
0197      * responding to input.
0198      *
0199      * openUrl() currently supports urls for local paths and those
0200      * using the 'ssh' protocol ( eg. "ssh://joebloggs@hostname" )
0201      */
0202     void openUrl(const QUrl &url);
0203 
0204     /**
0205      * update actions which are meaningful only when primary screen is in use.
0206      */
0207     void setupPrimaryScreenSpecificActions(bool use);
0208 
0209     /**
0210      * update actions which are closely related with the selected text.
0211      */
0212     void selectionChanged(const QString &selectedText);
0213 
0214     /**
0215      * close the associated session. This might involve user interaction for
0216      * confirmation.
0217      */
0218     void closeSession();
0219 
0220     /**  Increase font size */
0221     void increaseFontSize();
0222 
0223     /**  Decrease font size */
0224     void decreaseFontSize();
0225 
0226 private Q_SLOTS:
0227     // menu item handlers
0228     void openBrowser();
0229     void copy();
0230     void paste();
0231     void selectAll();
0232     void selectLine();
0233     void pasteFromX11Selection(); // shortcut only
0234     void copyInputActionsTriggered(QAction *action);
0235     void copyInputToAllTabs();
0236     void copyInputToSelectedTabs();
0237     void copyInputToNone();
0238     void editCurrentProfile();
0239     void changeCodec(QTextCodec *codec);
0240     void enableSearchBar(bool showSearchBar);
0241     void searchHistory(bool showSearchBar);
0242     void searchBarEvent();
0243     void searchFrom();
0244     void findNextInHistory();
0245     void findPreviousInHistory();
0246     void changeSearchMatch();
0247     void print_screen();
0248     void saveHistory();
0249     void showHistoryOptions();
0250     void clearHistory();
0251     void clearHistoryAndReset();
0252     void monitorActivity(bool monitor);
0253     void monitorSilence(bool monitor);
0254     void renameSession();
0255     void switchProfile(Profile::Ptr profile);
0256     void handleWebShortcutAction();
0257     void configureWebShortcuts();
0258     void sendSignal(QAction *action);
0259     void sendBackgroundColor();
0260 
0261     // other
0262     void prepareSwitchProfileMenu();
0263     void updateCodecAction();
0264     void showDisplayContextMenu(const QPoint &position);
0265     void movementKeyFromSearchBarReceived(QKeyEvent *event);
0266     void sessionStateChanged(int state);
0267     void sessionTitleChanged();
0268     void searchTextChanged(const QString &text);
0269     void searchCompleted(bool success);
0270     void searchClosed(); // called when the user clicks on the
0271     // history search bar's close button
0272 
0273     void updateFilterList(Profile::Ptr profile); // Called when the profile has changed, so we might need to change the list of filters
0274 
0275     void interactionHandler();
0276     void snapshot(); // called periodically as the user types
0277     // to take a snapshot of the state of the
0278     // foreground process in the terminal
0279 
0280     void highlightMatches(bool highlight);
0281     void scrollBackOptionsChanged(int mode, int lines);
0282     void sessionResizeRequest(const QSize &size);
0283     void trackOutput(QKeyEvent *event);  // move view to end of current output
0284     // when a key press occurs in the
0285     // display area
0286 
0287     void updateSearchFilter();
0288 
0289     void zmodemDownload();
0290     void zmodemUpload();
0291 
0292     // update actions related with selected text
0293     void updateCopyAction(const QString &selectedText);
0294     void updateWebSearchMenu();
0295 
0296 private:
0297     Q_DISABLE_COPY(SessionController)
0298 
0299     // begins the search
0300     // text - pattern to search for
0301     // direction - value from SearchHistoryTask::SearchDirection enum to specify
0302     //             the search direction
0303     void beginSearch(const QString &text, Enum::SearchDirection direction);
0304     QRegularExpression regexpFromSearchBarOptions() const;
0305     bool reverseSearchChecked() const;
0306     void setupCommonActions();
0307     void setupExtraActions();
0308     void removeSearchFilter(); // remove and delete the current search filter if set
0309     void setFindNextPrevEnabled(bool enabled);
0310     void listenForScreenWindowUpdates();
0311 
0312     /* Returns true if called within a KPart; false if called within Konsole. */
0313     bool isKonsolePart() const;
0314 
0315 private:
0316     void updateSessionIcon();
0317 
0318     QPointer<Session> _session;
0319     QPointer<TerminalDisplay> _view;
0320     SessionGroup *_copyToGroup;
0321 
0322     ProfileList *_profileList;
0323 
0324     QIcon _sessionIcon;
0325     QString _sessionIconName;
0326     int _previousState;
0327 
0328     RegExpFilter *_searchFilter;
0329     UrlFilter *_urlFilter;
0330     FileFilter *_fileFilter;
0331 
0332     QAction *_copyInputToAllTabsAction;
0333 
0334     QAction *_findAction;
0335     QAction *_findNextAction;
0336     QAction *_findPreviousAction;
0337 
0338     QTimer *_interactionTimer;
0339 
0340     int _searchStartLine;
0341     int _prevSearchResultLine;
0342     QPointer<IncrementalSearchBar> _searchBar;
0343 
0344     KCodecAction *_codecAction;
0345 
0346     KActionMenu *_switchProfileMenu;
0347     KActionMenu *_webSearchMenu;
0348 
0349     bool _listenForScreenWindowUpdates;
0350     bool _preventClose;
0351 
0352     bool _keepIconUntilInteraction;
0353 
0354     QString _selectedText;
0355 
0356     QAction *_showMenuAction;
0357 
0358     static QSet<SessionController *> _allControllers;
0359     static int _lastControllerId;
0360 
0361     QStringList _bookmarkValidProgramsToClear;
0362 
0363     bool _isSearchBarEnabled;
0364     QPointer<EditProfileDialog> _editProfileDialog;
0365 
0366     QString _searchText;
0367 };
0368 inline bool SessionController::isValid() const
0369 {
0370     return !_session.isNull() && !_view.isNull();
0371 }
0372 
0373 /**
0374  * Abstract class representing a task which can be performed on a group of sessions.
0375  *
0376  * Create a new instance of the appropriate sub-class for the task you want to perform and
0377  * call the addSession() method to add each session which needs to be processed.
0378  *
0379  * Finally, call the execute() method to perform the sub-class specific action on each
0380  * of the sessions.
0381  */
0382 class SessionTask : public QObject
0383 {
0384     Q_OBJECT
0385 
0386 public:
0387     explicit SessionTask(QObject *parent = nullptr);
0388 
0389     /**
0390      * Sets whether the task automatically deletes itself when the task has been finished.
0391      * Depending on whether the task operates synchronously or asynchronously, the deletion
0392      * may be scheduled immediately after execute() returns or it may happen some time later.
0393      */
0394     void setAutoDelete(bool enable);
0395     /** Returns true if the task automatically deletes itself.  See setAutoDelete() */
0396     bool autoDelete() const;
0397 
0398     /** Adds a new session to the group */
0399     void addSession(Session *session);
0400 
0401     /**
0402      * Executes the task on each of the sessions in the group.
0403      * The completed() signal is emitted when the task is finished, depending on the specific sub-class
0404      * execute() may be synchronous or asynchronous
0405      */
0406     virtual void execute() = 0;
0407 
0408 Q_SIGNALS:
0409     /**
0410      * Emitted when the task has completed.
0411      * Depending on the task this may occur just before execute() returns, or it
0412      * may occur later
0413      *
0414      * @param success Indicates whether the task completed successfully or not
0415      */
0416     void completed(bool success);
0417 
0418 protected:
0419     /** Returns a list of sessions in the group */
0420     QList< SessionPtr > sessions() const;
0421 
0422 private:
0423     bool _autoDelete;
0424     QList< SessionPtr > _sessions;
0425 };
0426 
0427 /**
0428  * A task which prompts for a URL for each session and saves that session's output
0429  * to the given URL
0430  */
0431 class SaveHistoryTask : public SessionTask
0432 {
0433     Q_OBJECT
0434 
0435 public:
0436     /** Constructs a new task to save session output to URLs */
0437     explicit SaveHistoryTask(QObject *parent = nullptr);
0438     ~SaveHistoryTask() Q_DECL_OVERRIDE;
0439 
0440     /**
0441      * Opens a save file dialog for each session in the group and begins saving
0442      * each session's history to the given URL.
0443      *
0444      * The data transfer is performed asynchronously and will continue after execute() returns.
0445      */
0446     void execute() Q_DECL_OVERRIDE;
0447 
0448 private Q_SLOTS:
0449     void jobDataRequested(KIO::Job *job, QByteArray &data);
0450     void jobResult(KJob *job);
0451 
0452 private:
0453     class SaveJob // structure to keep information needed to process
0454         // incoming data requests from jobs
0455     {
0456     public:
0457         SessionPtr session; // the session associated with a history save job
0458         int lastLineFetched; // the last line processed in the previous data request
0459         // set this to -1 at the start of the save job
0460 
0461         TerminalCharacterDecoder *decoder;  // decoder used to convert terminal characters
0462         // into output
0463     };
0464 
0465     QHash<KJob *, SaveJob> _jobSession;
0466 };
0467 
0468 //class SearchHistoryThread;
0469 /**
0470  * A task which searches through the output of sessions for matches for a given regular expression.
0471  * SearchHistoryTask operates on ScreenWindow instances rather than sessions added by addSession().
0472  * A screen window can be added to the list to search using addScreenWindow()
0473  *
0474  * When execute() is called, the search begins in the direction specified by searchDirection(),
0475  * starting at the position of the current selection.
0476  *
0477  * FIXME - This is not a proper implementation of SessionTask, in that it ignores sessions specified
0478  * with addSession()
0479  *
0480  * TODO - Implementation requirements:
0481  *          May provide progress feedback to the user when searching very large output logs.
0482  */
0483 class SearchHistoryTask : public SessionTask
0484 {
0485     Q_OBJECT
0486 
0487 public:
0488     /**
0489      * Constructs a new search task.
0490      */
0491     explicit SearchHistoryTask(QObject *parent = nullptr);
0492 
0493     /** Adds a screen window to the list to search when execute() is called. */
0494     void addScreenWindow(Session *session, ScreenWindow *searchWindow);
0495 
0496     /** Sets the regular expression which is searched for when execute() is called */
0497     void setRegExp(const QRegularExpression &expression);
0498     /** Returns the regular expression which is searched for when execute() is called */
0499     QRegularExpression regExp() const;
0500 
0501     /** Specifies the direction to search in when execute() is called. */
0502     void setSearchDirection(Enum::SearchDirection direction);
0503     /** Returns the current search direction.  See setSearchDirection(). */
0504     Enum::SearchDirection searchDirection() const;
0505 
0506     /** The line from which the search will be done **/
0507     void setStartLine(int line);
0508 
0509     /**
0510      * Performs a search through the session's history, starting at the position
0511      * of the current selection, in the direction specified by setSearchDirection().
0512      *
0513      * If it finds a match, the ScreenWindow specified in the constructor is
0514      * scrolled to the position where the match occurred and the selection
0515      * is set to the matching text.  execute() then returns immediately.
0516      *
0517      * To continue the search looking for further matches, call execute() again.
0518      */
0519     void execute() Q_DECL_OVERRIDE;
0520 
0521 private:
0522     typedef QPointer<ScreenWindow> ScreenWindowPtr;
0523 
0524     void executeOnScreenWindow(SessionPtr session, ScreenWindowPtr window);
0525     void highlightResult(ScreenWindowPtr window, int position);
0526 
0527     QMap< SessionPtr, ScreenWindowPtr > _windows;
0528     QRegularExpression _regExp;
0529     Enum::SearchDirection _direction;
0530     int _startLine;
0531 
0532     //static QPointer<SearchHistoryThread> _thread;
0533 };
0534 }
0535 
0536 #endif //SESSIONCONTROLLER_H