File indexing completed on 2018-09-18 18:16:00

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 action displayed in the session's context menu to hide or
0141      * show the menu bar.
0142      */
0143     void setShowMenuAction(QAction *action);
0144 
0145     EditProfileDialog *profileDialogPointer();
0146 
0147     // reimplemented
0148     QUrl url() const Q_DECL_OVERRIDE;
0149     QString currentDir() const Q_DECL_OVERRIDE;
0150     void rename() Q_DECL_OVERRIDE;
0151     bool confirmClose() const Q_DECL_OVERRIDE;
0152     virtual bool confirmForceClose() const;
0153 
0154     // Reimplemented to watch for events happening to the view
0155     bool eventFilter(QObject *watched, QEvent *event) Q_DECL_OVERRIDE;
0156 
0157     /** Returns the set of all controllers that exist. */
0158     static QSet<SessionController *> allControllers()
0159     {
0160         return _allControllers;
0161     }
0162 
0163     /* Returns true if called within a KPart; false if called within Konsole. */
0164     bool isKonsolePart() const;
0165     bool isReadOnly() const;
0166 
0167 Q_SIGNALS:
0168     /**
0169      * Emitted when the view associated with the controller is focused.
0170      * This can be used by other classes to plug the controller's actions into a window's
0171      * menus.
0172      */
0173     void focused(SessionController *controller);
0174 
0175     void rawTitleChanged();
0176 
0177     /**
0178      * Emitted when the current working directory of the session associated with
0179      * the controller is changed.
0180      */
0181     void currentDirectoryChanged(const QString &dir);
0182 
0183     /**
0184      * Emitted when the user changes the tab title.
0185      */
0186     void tabRenamedByUser(bool renamed) const;
0187 
0188 public Q_SLOTS:
0189     /**
0190      * Issues a command to the session to navigate to the specified URL.
0191      * This may not succeed if the foreground program does not understand
0192      * the command sent to it ( 'cd path' for local URLs ) or is not
0193      * responding to input.
0194      *
0195      * openUrl() currently supports urls for local paths and those
0196      * using the 'ssh' protocol ( eg. "ssh://joebloggs@hostname" )
0197      */
0198     void openUrl(const QUrl &url);
0199 
0200     /**
0201      * update actions which are meaningful only when primary screen is in use.
0202      */
0203     void setupPrimaryScreenSpecificActions(bool use);
0204 
0205     /**
0206      * update actions which are closely related with the selected text.
0207      */
0208     void selectionChanged(const QString &selectedText);
0209 
0210     /**
0211      * close the associated session. This might involve user interaction for
0212      * confirmation.
0213      */
0214     void closeSession();
0215 
0216     /**  Increase font size */
0217     void increaseFontSize();
0218 
0219     /**  Decrease font size */
0220     void decreaseFontSize();
0221 
0222     /** Reset font size */
0223     void resetFontSize();
0224 
0225 private Q_SLOTS:
0226     // menu item handlers
0227     void openBrowser();
0228     void copy();
0229     void paste();
0230     void selectAll();
0231     void selectLine();
0232     void pasteFromX11Selection(); // shortcut only
0233     void copyInputActionsTriggered(QAction *action);
0234     void copyInputToAllTabs();
0235     void copyInputToSelectedTabs();
0236     void copyInputToNone();
0237     void editCurrentProfile();
0238     void changeCodec(QTextCodec *codec);
0239     void enableSearchBar(bool showSearchBar);
0240     void searchHistory(bool showSearchBar);
0241     void searchBarEvent();
0242     void searchFrom();
0243     void findNextInHistory();
0244     void findPreviousInHistory();
0245     void changeSearchMatch();
0246     void print_screen();
0247     void saveHistory();
0248     void showHistoryOptions();
0249     void clearHistory();
0250     void clearHistoryAndReset();
0251     void monitorActivity(bool monitor);
0252     void monitorSilence(bool monitor);
0253     void renameSession();
0254     void switchProfile(Profile::Ptr profile);
0255     void handleWebShortcutAction();
0256     void configureWebShortcuts();
0257     void sendSignal(QAction *action);
0258     void sendBackgroundColor();
0259     void toggleReadOnly();
0260 
0261     // other
0262     void setupSearchBar();
0263     void prepareSwitchProfileMenu();
0264     void updateCodecAction();
0265     void showDisplayContextMenu(const QPoint &position);
0266     void movementKeyFromSearchBarReceived(QKeyEvent *event);
0267     void sessionStateChanged(int state);
0268     void sessionAttributeChanged();
0269     void sessionReadOnlyChanged();
0270     void searchTextChanged(const QString &text);
0271     void searchCompleted(bool success);
0272     void searchClosed(); // called when the user clicks on the
0273     // history search bar's close button
0274 
0275     void updateFilterList(Profile::Ptr profile); // Called when the profile has changed, so we might need to change the list of filters
0276 
0277     void interactionHandler();
0278     void snapshot(); // called periodically as the user types
0279     // to take a snapshot of the state of the
0280     // foreground process in the terminal
0281 
0282     void highlightMatches(bool highlight);
0283     void scrollBackOptionsChanged(int mode, int lines);
0284     void sessionResizeRequest(const QSize &size);
0285     void trackOutput(QKeyEvent *event);  // move view to end of current output
0286     // when a key press occurs in the
0287     // display area
0288 
0289     void updateSearchFilter();
0290 
0291     void zmodemDownload();
0292     void zmodemUpload();
0293 
0294     // update actions related with selected text
0295     void updateCopyAction(const QString &selectedText);
0296     void updateWebSearchMenu();
0297 
0298 private:
0299     Q_DISABLE_COPY(SessionController)
0300 
0301     // begins the search
0302     // text - pattern to search for
0303     // direction - value from SearchHistoryTask::SearchDirection enum to specify
0304     //             the search direction
0305     void beginSearch(const QString &text, Enum::SearchDirection direction);
0306     QRegularExpression regexpFromSearchBarOptions() const;
0307     bool reverseSearchChecked() const;
0308     void setupCommonActions();
0309     void setupExtraActions();
0310     void removeSearchFilter(); // remove and delete the current search filter if set
0311     void setFindNextPrevEnabled(bool enabled);
0312     void listenForScreenWindowUpdates();
0313 
0314 private:
0315     void updateSessionIcon();
0316     void updateReadOnlyActionStates();
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 
0343     KCodecAction *_codecAction;
0344 
0345     KActionMenu *_switchProfileMenu;
0346     KActionMenu *_webSearchMenu;
0347 
0348     bool _listenForScreenWindowUpdates;
0349     bool _preventClose;
0350 
0351     bool _keepIconUntilInteraction;
0352 
0353     QString _selectedText;
0354 
0355     QAction *_showMenuAction;
0356 
0357     static QSet<SessionController *> _allControllers;
0358     static int _lastControllerId;
0359 
0360     QStringList _bookmarkValidProgramsToClear;
0361 
0362     bool _isSearchBarEnabled;
0363     QPointer<EditProfileDialog> _editProfileDialog;
0364 
0365     QString _searchText;
0366     QPointer<IncrementalSearchBar> _searchBar;
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