1 | /* |
2 | Copyright 2006-2008 by Robert Knight <robertknight@gmail.com> |
3 | Copyright 2009 by Thomas Dreibholz <dreibh@iem.uni-due.de> |
4 | |
5 | This program is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published by |
7 | the Free Software Foundation; either version 2 of the License, or |
8 | (at your option) any later version. |
9 | |
10 | This program is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | GNU General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU General Public License |
16 | along with this program; if not, write to the Free Software |
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
18 | 02110-1301 USA. |
19 | */ |
20 | |
21 | #ifndef SESSIONCONTROLLER_H |
22 | #define SESSIONCONTROLLER_H |
23 | |
24 | // Qt |
25 | #include <QtCore/QList> |
26 | #include <QtCore/QSet> |
27 | #include <QtCore/QPointer> |
28 | #include <QtCore/QString> |
29 | #include <QtCore/QHash> |
30 | |
31 | // KDE |
32 | #include <KIcon> |
33 | #include <KXMLGUIClient> |
34 | |
35 | // Konsole |
36 | #include "ViewProperties.h" |
37 | #include "Profile.h" |
38 | |
39 | namespace KIO |
40 | { |
41 | class Job; |
42 | } |
43 | |
44 | class QAction; |
45 | class QTextCodec; |
46 | class QKeyEvent; |
47 | class QTimer; |
48 | |
49 | class KCodecAction; |
50 | class KUrl; |
51 | class KJob; |
52 | class KAction; |
53 | class ; |
54 | |
55 | namespace Konsole |
56 | { |
57 | class Session; |
58 | class SessionGroup; |
59 | class ScreenWindow; |
60 | class TerminalDisplay; |
61 | class IncrementalSearchBar; |
62 | class ProfileList; |
63 | class UrlFilter; |
64 | class RegExpFilter; |
65 | class EditProfileDialog; |
66 | |
67 | // SaveHistoryTask |
68 | class TerminalCharacterDecoder; |
69 | |
70 | typedef QPointer<Session> SessionPtr; |
71 | |
72 | /** |
73 | * Provides the menu actions to manipulate a single terminal session and view pair. |
74 | * The actions provided by this class are defined in the sessionui.rc XML file. |
75 | * |
76 | * SessionController monitors the session and provides access to basic information |
77 | * about the session such as title(), icon() and currentDir(). SessionController |
78 | * provides notifications of activity in the session via the activity() signal. |
79 | * |
80 | * When the controlled view receives the focus, the focused() signal is emitted |
81 | * with a pointer to the controller. This can be used by main application window |
82 | * which contains the view to plug the controller's actions into the menu when |
83 | * the view is focused. |
84 | */ |
85 | class KONSOLEPRIVATE_EXPORT SessionController : public ViewProperties , public KXMLGUIClient |
86 | { |
87 | Q_OBJECT |
88 | |
89 | public: |
90 | enum CopyInputToEnum { |
91 | /** Copy keyboard input to all the other tabs in current window */ |
92 | CopyInputToAllTabsMode = 0 , |
93 | |
94 | /** Copy keyboard input to user selected tabs in current window */ |
95 | CopyInputToSelectedTabsMode = 1 , |
96 | |
97 | /** Do not copy keyboard input to other tabs */ |
98 | CopyInputToNoneMode = 2 |
99 | }; |
100 | |
101 | /** |
102 | * Constructs a new SessionController which operates on @p session and @p view. |
103 | */ |
104 | SessionController(Session* session , TerminalDisplay* view, QObject* parent); |
105 | ~SessionController(); |
106 | |
107 | /** Returns the session associated with this controller */ |
108 | QPointer<Session> session() { |
109 | return _session; |
110 | } |
111 | /** Returns the view associated with this controller */ |
112 | QPointer<TerminalDisplay> view() { |
113 | return _view; |
114 | } |
115 | |
116 | /** |
117 | * Returns the "window title" of the associated session. |
118 | */ |
119 | QString userTitle() const; |
120 | |
121 | /** |
122 | * Returns true if the controller is valid. |
123 | * A valid controller is one which has a non-null session() and view(). |
124 | * |
125 | * Equivalent to "!session().isNull() && !view().isNull()" |
126 | */ |
127 | bool isValid() const; |
128 | |
129 | /** Set the start line from which the next search will be done **/ |
130 | void setSearchStartTo(int line); |
131 | |
132 | /** set start line to the first or last line (depending on the reverse search |
133 | * setting) in the terminal display **/ |
134 | void setSearchStartToWindowCurrentLine(); |
135 | |
136 | /** |
137 | * Sets the widget used for searches through the session's output. |
138 | * |
139 | * When the user clicks on the "Search Output" menu action the @p searchBar 's |
140 | * show() method will be called. The SessionController will then connect to the search |
141 | * bar's signals to update the search when the widget's controls are pressed. |
142 | */ |
143 | void setSearchBar(IncrementalSearchBar* searchBar); |
144 | /** |
145 | * see setSearchBar() |
146 | */ |
147 | IncrementalSearchBar* searchBar() const; |
148 | |
149 | /** |
150 | * Sets the action displayed in the session's context menu to hide or |
151 | * show the menu bar. |
152 | */ |
153 | void (QAction* action); |
154 | |
155 | EditProfileDialog* profileDialogPointer(); |
156 | |
157 | // reimplemented |
158 | virtual KUrl url() const; |
159 | virtual QString currentDir() const; |
160 | virtual void rename(); |
161 | virtual bool confirmClose() const; |
162 | virtual bool confirmForceClose() const; |
163 | |
164 | // Reimplemented to watch for events happening to the view |
165 | virtual bool eventFilter(QObject* watched , QEvent* event); |
166 | |
167 | /** Returns the set of all controllers that exist. */ |
168 | static QSet<SessionController*> allControllers() { |
169 | return _allControllers; |
170 | } |
171 | |
172 | signals: |
173 | /** |
174 | * Emitted when the view associated with the controller is focused. |
175 | * This can be used by other classes to plug the controller's actions into a window's |
176 | * menus. |
177 | */ |
178 | void focused(SessionController* controller); |
179 | |
180 | void rawTitleChanged(); |
181 | |
182 | /** |
183 | * Emitted when the current working directory of the session associated with |
184 | * the controller is changed. |
185 | */ |
186 | void currentDirectoryChanged(const QString& dir); |
187 | |
188 | public slots: |
189 | /** |
190 | * Issues a command to the session to navigate to the specified URL. |
191 | * This may not succeed if the foreground program does not understand |
192 | * the command sent to it ( 'cd path' for local URLs ) or is not |
193 | * responding to input. |
194 | * |
195 | * openUrl() currently supports urls for local paths and those |
196 | * using the 'ssh' protocol ( eg. "ssh://joebloggs@hostname" ) |
197 | */ |
198 | void openUrl(const KUrl& url); |
199 | |
200 | /** |
201 | * update actions which are meaningful only when primary screen is in use. |
202 | */ |
203 | void setupPrimaryScreenSpecificActions(bool use); |
204 | |
205 | /** |
206 | * update actions which are closely related with the selected text. |
207 | */ |
208 | void selectionChanged(const QString& selectedText); |
209 | |
210 | /** |
211 | * close the associated session. This might involve user interaction for |
212 | * confirmation. |
213 | */ |
214 | void closeSession(); |
215 | |
216 | /** Increase font size */ |
217 | void increaseFontSize(); |
218 | |
219 | /** Decrease font size */ |
220 | void decreaseFontSize(); |
221 | |
222 | private slots: |
223 | // menu item handlers |
224 | void openBrowser(); |
225 | void copy(); |
226 | void paste(); |
227 | void selectAll(); |
228 | void selectLine(); |
229 | void pasteFromX11Selection(); // shortcut only |
230 | void copyInputActionsTriggered(QAction* action); |
231 | void copyInputToAllTabs(); |
232 | void copyInputToSelectedTabs(); |
233 | void copyInputToNone(); |
234 | void editCurrentProfile(); |
235 | void changeCodec(QTextCodec* codec); |
236 | void enableSearchBar(bool showSearchBar); |
237 | void searchHistory(bool showSearchBar); |
238 | void searchBarEvent(); |
239 | void searchFrom(); |
240 | void findNextInHistory(); |
241 | void findPreviousInHistory(); |
242 | void changeSearchMatch(); |
243 | void print_screen(); |
244 | void saveHistory(); |
245 | void showHistoryOptions(); |
246 | void clearHistory(); |
247 | void clearHistoryAndReset(); |
248 | void monitorActivity(bool monitor); |
249 | void monitorSilence(bool monitor); |
250 | void renameSession(); |
251 | void switchProfile(Profile::Ptr profile); |
252 | void handleWebShortcutAction(); |
253 | void configureWebShortcuts(); |
254 | void sendSignal(QAction* action); |
255 | |
256 | // other |
257 | void (); |
258 | void updateCodecAction(); |
259 | void (const QPoint& position); |
260 | void movementKeyFromSearchBarReceived(QKeyEvent *event); |
261 | void sessionStateChanged(int state); |
262 | void sessionTitleChanged(); |
263 | void searchTextChanged(const QString& text); |
264 | void searchCompleted(bool success); |
265 | void searchClosed(); // called when the user clicks on the |
266 | // history search bar's close button |
267 | |
268 | void interactionHandler(); |
269 | void snapshot(); // called periodically as the user types |
270 | // to take a snapshot of the state of the |
271 | // foreground process in the terminal |
272 | |
273 | void requireUrlFilterUpdate(); |
274 | void highlightMatches(bool highlight); |
275 | void scrollBackOptionsChanged(int mode , int lines); |
276 | void sessionResizeRequest(const QSize& size); |
277 | void trackOutput(QKeyEvent* event); // move view to end of current output |
278 | // when a key press occurs in the |
279 | // display area |
280 | |
281 | void updateSearchFilter(); |
282 | |
283 | void zmodemDownload(); |
284 | void zmodemUpload(); |
285 | |
286 | /* Returns true if called within a KPart; false if called within Konsole. */ |
287 | bool isKonsolePart() const; |
288 | |
289 | // update actions related with selected text |
290 | void updateCopyAction(const QString& selectedText); |
291 | void (); |
292 | |
293 | private: |
294 | // begins the search |
295 | // text - pattern to search for |
296 | // direction - value from SearchHistoryTask::SearchDirection enum to specify |
297 | // the search direction |
298 | void beginSearch(const QString& text , int direction); |
299 | QRegExp regexpFromSearchBarOptions(); |
300 | bool reverseSearchChecked() const; |
301 | void setupCommonActions(); |
302 | void (); |
303 | void removeSearchFilter(); // remove and delete the current search filter if set |
304 | void setFindNextPrevEnabled(bool enabled); |
305 | void listenForScreenWindowUpdates(); |
306 | |
307 | private: |
308 | void updateSessionIcon(); |
309 | |
310 | QPointer<Session> _session; |
311 | QPointer<TerminalDisplay> _view; |
312 | SessionGroup* _copyToGroup; |
313 | |
314 | ProfileList* _profileList; |
315 | |
316 | KIcon _sessionIcon; |
317 | QString _sessionIconName; |
318 | int _previousState; |
319 | |
320 | UrlFilter* _viewUrlFilter; |
321 | RegExpFilter* _searchFilter; |
322 | |
323 | KAction* _copyInputToAllTabsAction; |
324 | |
325 | KAction* _findAction; |
326 | KAction* _findNextAction; |
327 | KAction* _findPreviousAction; |
328 | |
329 | QTimer* _interactionTimer; |
330 | |
331 | bool _urlFilterUpdateRequired; |
332 | |
333 | int _searchStartLine; |
334 | int _prevSearchResultLine; |
335 | QPointer<IncrementalSearchBar> _searchBar; |
336 | |
337 | KCodecAction* _codecAction; |
338 | |
339 | KActionMenu* ; |
340 | KActionMenu* ; |
341 | |
342 | bool _listenForScreenWindowUpdates; |
343 | bool _preventClose; |
344 | |
345 | bool _keepIconUntilInteraction; |
346 | |
347 | QString _selectedText; |
348 | |
349 | QAction* ; |
350 | |
351 | static QSet<SessionController*> _allControllers; |
352 | static int _lastControllerId; |
353 | static const KIcon _activityIcon; |
354 | static const KIcon _silenceIcon; |
355 | static const KIcon _broadcastIcon; |
356 | |
357 | QStringList _bookmarkValidProgramsToClear; |
358 | |
359 | bool _isSearchBarEnabled; |
360 | QWeakPointer<EditProfileDialog> _editProfileDialog; |
361 | |
362 | QString _searchText; |
363 | }; |
364 | inline bool SessionController::isValid() const |
365 | { |
366 | return !_session.isNull() && !_view.isNull(); |
367 | } |
368 | |
369 | /** |
370 | * Abstract class representing a task which can be performed on a group of sessions. |
371 | * |
372 | * Create a new instance of the appropriate sub-class for the task you want to perform and |
373 | * call the addSession() method to add each session which needs to be processed. |
374 | * |
375 | * Finally, call the execute() method to perform the sub-class specific action on each |
376 | * of the sessions. |
377 | */ |
378 | class SessionTask : public QObject |
379 | { |
380 | Q_OBJECT |
381 | |
382 | public: |
383 | explicit SessionTask(QObject* parent = 0); |
384 | |
385 | /** |
386 | * Sets whether the task automatically deletes itself when the task has been finished. |
387 | * Depending on whether the task operates synchronously or asynchronously, the deletion |
388 | * may be scheduled immediately after execute() returns or it may happen some time later. |
389 | */ |
390 | void setAutoDelete(bool enable); |
391 | /** Returns true if the task automatically deletes itself. See setAutoDelete() */ |
392 | bool autoDelete() const; |
393 | |
394 | /** Adds a new session to the group */ |
395 | void addSession(Session* session); |
396 | |
397 | /** |
398 | * Executes the task on each of the sessions in the group. |
399 | * The completed() signal is emitted when the task is finished, depending on the specific sub-class |
400 | * execute() may be synchronous or asynchronous |
401 | */ |
402 | virtual void execute() = 0; |
403 | |
404 | signals: |
405 | /** |
406 | * Emitted when the task has completed. |
407 | * Depending on the task this may occur just before execute() returns, or it |
408 | * may occur later |
409 | * |
410 | * @param success Indicates whether the task completed successfully or not |
411 | */ |
412 | void completed(bool success); |
413 | |
414 | protected: |
415 | /** Returns a list of sessions in the group */ |
416 | QList< SessionPtr > sessions() const; |
417 | |
418 | private: |
419 | bool _autoDelete; |
420 | QList< SessionPtr > _sessions; |
421 | }; |
422 | |
423 | /** |
424 | * A task which prompts for a URL for each session and saves that session's output |
425 | * to the given URL |
426 | */ |
427 | class SaveHistoryTask : public SessionTask |
428 | { |
429 | Q_OBJECT |
430 | |
431 | public: |
432 | /** Constructs a new task to save session output to URLs */ |
433 | explicit SaveHistoryTask(QObject* parent = 0); |
434 | virtual ~SaveHistoryTask(); |
435 | |
436 | /** |
437 | * Opens a save file dialog for each session in the group and begins saving |
438 | * each session's history to the given URL. |
439 | * |
440 | * The data transfer is performed asynchronously and will continue after execute() returns. |
441 | */ |
442 | virtual void execute(); |
443 | |
444 | private slots: |
445 | void jobDataRequested(KIO::Job* job , QByteArray& data); |
446 | void jobResult(KJob* job); |
447 | |
448 | private: |
449 | class SaveJob // structure to keep information needed to process |
450 | // incoming data requests from jobs |
451 | { |
452 | public: |
453 | SessionPtr session; // the session associated with a history save job |
454 | int lastLineFetched; // the last line processed in the previous data request |
455 | // set this to -1 at the start of the save job |
456 | |
457 | TerminalCharacterDecoder* decoder; // decoder used to convert terminal characters |
458 | // into output |
459 | }; |
460 | |
461 | QHash<KJob*, SaveJob> _jobSession; |
462 | }; |
463 | |
464 | //class SearchHistoryThread; |
465 | /** |
466 | * A task which searches through the output of sessions for matches for a given regular expression. |
467 | * SearchHistoryTask operates on ScreenWindow instances rather than sessions added by addSession(). |
468 | * A screen window can be added to the list to search using addScreenWindow() |
469 | * |
470 | * When execute() is called, the search begins in the direction specified by searchDirection(), |
471 | * starting at the position of the current selection. |
472 | * |
473 | * FIXME - This is not a proper implementation of SessionTask, in that it ignores sessions specified |
474 | * with addSession() |
475 | * |
476 | * TODO - Implementation requirements: |
477 | * May provide progress feedback to the user when searching very large output logs. |
478 | */ |
479 | class SearchHistoryTask : public SessionTask |
480 | { |
481 | Q_OBJECT |
482 | |
483 | public: |
484 | /** |
485 | * This enum describes the strategies available for searching through the |
486 | * session's output. |
487 | */ |
488 | enum SearchDirection { |
489 | /** Searches forwards through the output, starting at the current selection. */ |
490 | ForwardsSearch, |
491 | /** Searches backwards through the output, starting at the current selection. */ |
492 | BackwardsSearch |
493 | }; |
494 | |
495 | /** |
496 | * Constructs a new search task. |
497 | */ |
498 | explicit SearchHistoryTask(QObject* parent = 0); |
499 | |
500 | /** Adds a screen window to the list to search when execute() is called. */ |
501 | void addScreenWindow(Session* session , ScreenWindow* searchWindow); |
502 | |
503 | /** Sets the regular expression which is searched for when execute() is called */ |
504 | void setRegExp(const QRegExp& regExp); |
505 | /** Returns the regular expression which is searched for when execute() is called */ |
506 | QRegExp regExp() const; |
507 | |
508 | /** Specifies the direction to search in when execute() is called. */ |
509 | void setSearchDirection(SearchDirection direction); |
510 | /** Returns the current search direction. See setSearchDirection(). */ |
511 | SearchDirection searchDirection() const; |
512 | |
513 | /** The line from which the search will be done **/ |
514 | void setStartLine(int startLine); |
515 | |
516 | /** |
517 | * Performs a search through the session's history, starting at the position |
518 | * of the current selection, in the direction specified by setSearchDirection(). |
519 | * |
520 | * If it finds a match, the ScreenWindow specified in the constructor is |
521 | * scrolled to the position where the match occurred and the selection |
522 | * is set to the matching text. execute() then returns immediately. |
523 | * |
524 | * To continue the search looking for further matches, call execute() again. |
525 | */ |
526 | virtual void execute(); |
527 | |
528 | private: |
529 | typedef QPointer<ScreenWindow> ScreenWindowPtr; |
530 | |
531 | void executeOnScreenWindow(SessionPtr session , ScreenWindowPtr window); |
532 | void highlightResult(ScreenWindowPtr window , int position); |
533 | |
534 | QMap< SessionPtr , ScreenWindowPtr > _windows; |
535 | QRegExp _regExp; |
536 | SearchDirection _direction; |
537 | int _startLine; |
538 | |
539 | //static QPointer<SearchHistoryThread> _thread; |
540 | }; |
541 | } |
542 | |
543 | #endif //SESSIONCONTROLLER_H |
544 | |
545 | |