1 /* 2 * Copyright (C) 2009, 2010, 2011, 2012, 2013, 2017 Nicolas Bonnefon 3 * and other contributors 4 * 5 * This file is part of glogg. 6 * 7 * glogg is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * glogg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with glogg. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #ifndef ABSTRACTLOGVIEW_H 22 #define ABSTRACTLOGVIEW_H 23 24 #include <QAbstractScrollArea> 25 #include <QBasicTimer> 26 27 #ifdef GLOGG_PERF_MEASURE_FPS 28 # include "perfcounter.h" 29 #endif 30 31 #include "selection.h" 32 #include "quickfind.h" 33 #include "overviewwidget.h" 34 #include "quickfindmux.h" 35 #include "viewtools.h" 36 37 class QMenu; 38 class QAction; 39 class AbstractLogData; 40 41 class LineChunk 42 { 43 public: 44 enum ChunkType { 45 Normal, 46 Highlighted, 47 Selected, 48 }; 49 50 LineChunk( int first_col, int end_col, ChunkType type ); 51 52 int start() const { return start_; } 53 int end() const { return end_; } 54 ChunkType type() const { return type_; } 55 56 // Returns 'true' if the selection is part of this chunk 57 // (at least partially), if so, it should be replaced by the list returned 58 QList<LineChunk> select( int selection_start, int selection_end ) const; 59 60 private: 61 int start_; 62 int end_; 63 ChunkType type_; 64 }; 65 66 // Utility class for syntax colouring. 67 // It stores the chunks of line to draw 68 // each chunk having a different colour 69 class LineDrawer 70 { 71 public: 72 LineDrawer( const QColor& back_color) : 73 list(), backColor_( back_color ) { }; 74 75 // Add a chunk of line using the given colours. 76 // Both first_col and last_col are included 77 // An empty chunk will be ignored. 78 // the first column will be set to 0 if negative 79 // The column are relative to the screen 80 void addChunk( int first_col, int last_col, QColor fore, QColor back ); 81 void addChunk( const LineChunk& chunk, QColor fore, QColor back ); 82 83 // Draw the current line of text using the given painter, 84 // in the passed block (in pixels) 85 // The line must be cut to fit on the screen. 86 // leftExtraBackgroundPx is the an extra margin to start drawing 87 // the coloured // background, going all the way to the element 88 // left of the line looks better. 89 void draw( QPainter& painter, int xPos, int yPos, 90 int line_width, const QString& line, 91 int leftExtraBackgroundPx ); 92 93 private: 94 class Chunk { 95 public: 96 // Create a new chunk 97 Chunk( int start, int length, QColor fore, QColor back ) 98 : start_( start ), length_( length ), 99 foreColor_ ( fore ), backColor_ ( back ) { }; 100 101 // Accessors 102 int start() const { return start_; } 103 int length() const { return length_; } 104 const QColor& foreColor() const { return foreColor_; } 105 const QColor& backColor() const { return backColor_; } 106 107 private: 108 int start_; 109 int length_; 110 QColor foreColor_; 111 QColor backColor_; 112 }; 113 QList<Chunk> list; 114 QColor backColor_; 115 }; 116 117 118 // Utility class representing a buffer for number entered on the keyboard 119 // The buffer keep at most 7 digits, and reset itself after a timeout. 120 class DigitsBuffer : public QObject 121 { 122 Q_OBJECT 123 124 public: 125 DigitsBuffer(); 126 127 // Reset the buffer. 128 void reset(); 129 // Add a single digit to the buffer (discarded if it's not a digit), 130 // the timeout timer is reset. 131 void add( char character ); 132 // Get the content of the buffer (0 if empty) and reset it. 133 int content(); 134 135 protected: 136 void timerEvent( QTimerEvent* event ); 137 138 private: 139 // Duration of the timeout in milliseconds. 140 static const int timeout_; 141 142 QString digits_; 143 144 QBasicTimer timer_; 145 }; 146 147 class Overview; 148 149 // Base class representing the log view widget. 150 // It can be either the top (full) or bottom (filtered) view. 151 class AbstractLogView : 152 public QAbstractScrollArea, public SearchableWidgetInterface 153 { 154 Q_OBJECT 155 156 public: 157 // Constructor of the widget, the data set is passed. 158 // The caller retains ownership of the data set. 159 // The pointer to the QFP is used for colouring and QuickFind searches 160 AbstractLogView( const AbstractLogData* newLogData, 161 const QuickFindPattern* const quickFind, QWidget* parent=0 ); 162 ~AbstractLogView(); 163 164 // Refresh the widget when the data set has changed. 165 void updateData(); 166 // Instructs the widget to update it's content geometry, 167 // used when the font is changed. 168 void updateDisplaySize(); 169 // Return the line number of the top line of the view 170 int getTopLine() const; 171 // Return the text of the current selection. 172 QString getSelection() const; 173 // Instructs the widget to select the whole text. 174 void selectAll(); 175 176 bool isFollowEnabled() const { return followMode_; } 177 178 protected: 179 virtual void mousePressEvent( QMouseEvent* mouseEvent ); 180 virtual void mouseMoveEvent( QMouseEvent* mouseEvent ); 181 virtual void mouseReleaseEvent( QMouseEvent* ); 182 virtual void mouseDoubleClickEvent( QMouseEvent* mouseEvent ); 183 virtual void timerEvent( QTimerEvent* timerEvent ); 184 virtual void changeEvent( QEvent* changeEvent ); 185 virtual void paintEvent( QPaintEvent* paintEvent ); 186 virtual void resizeEvent( QResizeEvent* resizeEvent ); 187 virtual void scrollContentsBy( int dx, int dy ); 188 virtual void keyPressEvent( QKeyEvent* keyEvent ); 189 virtual void wheelEvent( QWheelEvent* wheelEvent ); 190 virtual bool event( QEvent * e ); 191 192 // Must be implemented to return wether the line number is 193 // a match, a mark or just a normal line (used for coloured bullets) 194 enum LineType { Normal, Marked, Match }; 195 virtual LineType lineType( int lineNumber ) const = 0; 196 197 // Line number to display for line at the given index 198 virtual qint64 displayLineNumber( int lineNumber ) const; 199 virtual qint64 maxDisplayLineNumber() const; 200 201 // Get the overview associated with this view, or NULL if there is none 202 Overview* getOverview() const { return overview_; } 203 // Set the Overview and OverviewWidget 204 void setOverview( Overview* overview, OverviewWidget* overview_widget ); 205 206 // Returns the current "position" of the view as a line number, 207 // it is either the selected line or the middle of the view. 208 LineNumber getViewPosition() const; 209 210 signals: 211 // Sent when a new line has been selected by the user. 212 void newSelection(int line); 213 // Sent up to the MainWindow to enable/disable the follow mode 214 void followModeChanged( bool enabled ); 215 // Sent when the view wants the QuickFind widget pattern to change. 216 void changeQuickFind( const QString& newPattern, 217 QuickFindMux::QFDirection newDirection ); 218 // Sent up when the current line number is updated 219 void updateLineNumber( int line ); 220 // Sent up when quickFind wants to show a message to the user. 221 void notifyQuickFind( const QFNotification& message ); 222 // Sent up when quickFind wants to clear the notification. 223 void clearQuickFindNotification(); 224 // Sent when the view ask for a line to be marked 225 // (click in the left margin). 226 void markLine( qint64 line ); 227 // Sent up when the user wants to add the selection to the search 228 void addToSearch( const QString& selection ); 229 // Sent up when the mouse is hovered over a line's margin 230 void mouseHoveredOverLine( qint64 line ); 231 // Sent up when the mouse leaves a line's margin 232 void mouseLeftHoveringZone(); 233 // Sent up for view initiated quickfind searches 234 void searchNext(); 235 void searchPrevious(); 236 // Sent up when the user has moved within the view 237 void activity(); 238 239 public slots: 240 // Makes the widget select and display the passed line. 241 // Scrolling as necessary 242 void selectAndDisplayLine( int line ); 243 244 // Use the current QFP to go and select the next match. 245 virtual void searchForward(); 246 // Use the current QFP to go and select the previous match. 247 virtual void searchBackward(); 248 249 // Use the current QFP to go and select the next match (incremental) 250 virtual void incrementallySearchForward(); 251 // Use the current QFP to go and select the previous match (incremental) 252 virtual void incrementallySearchBackward(); 253 // Stop the current incremental search (typically when user press return) 254 virtual void incrementalSearchStop(); 255 // Abort the current incremental search (typically when user press esc) 256 virtual void incrementalSearchAbort(); 257 258 // Signals the follow mode has been enabled. 259 void followSet( bool checked ); 260 261 // Signal the on/off status of the overview has been changed. 262 void refreshOverview(); 263 264 // Make the view jump to the specified line, regardless of weither it 265 // is on the screen or not. 266 // (does NOT emit followDisabled() ) 267 void jumpToLine( int line ); 268 269 // Configure the setting of whether to show line number margin 270 void setLineNumbersVisible( bool lineNumbersVisible ); 271 272 // Force the next refresh to fully redraw the view by invalidating the cache. 273 // To be used if the data might have changed. 274 void forceRefresh(); 275 276 private slots: 277 void handlePatternUpdated(); 278 void addToSearch(); 279 void findNextSelected(); 280 void findPreviousSelected(); 281 void copy(); 282 283 private: 284 // Graphic parameters 285 static constexpr int OVERVIEW_WIDTH = 27; 286 static constexpr int HOOK_THRESHOLD = 600; 287 static constexpr int PULL_TO_FOLLOW_HOOKED_HEIGHT = 10; 288 289 // Width of the bullet zone, including decoration 290 int bulletZoneWidthPx_; 291 292 // Total size of all margins and decorations in pixels 293 int leftMarginPx_; 294 295 // Digits buffer (for numeric keyboard entry) 296 DigitsBuffer digitsBuffer_; 297 298 // Follow mode 299 bool followMode_; 300 301 // ElasticHook for follow mode 302 ElasticHook followElasticHook_; 303 304 // Whether to show line numbers or not 305 bool lineNumbersVisible_; 306 307 // Pointer to the CrawlerWidget's data set 308 const AbstractLogData* logData; 309 310 // Pointer to the Overview object 311 Overview* overview_; 312 313 // Pointer to the OverviewWidget, this class doesn't own it, 314 // but is responsible for displaying it (for purely aesthetic 315 // reasons). 316 OverviewWidget* overviewWidget_; 317 318 bool selectionStarted_; 319 // Start of the selection (characters) 320 QPoint selectionStartPos_; 321 // Current end of the selection (characters) 322 QPoint selectionCurrentEndPos_; 323 QBasicTimer autoScrollTimer_; 324 325 // Hovering state 326 // Last line that has been hoovered on, -1 if none 327 qint64 lastHoveredLine_; 328 329 // Marks (left margin click) 330 bool markingClickInitiated_; 331 qint64 markingClickLine_; 332 333 Selection selection_; 334 335 // Position of the view, those are crucial to control drawing 336 // firstLine gives the position of the view, 337 // lastLineAligned == true make the bottom of the last line aligned 338 // rather than the top of the top one. 339 LineNumber firstLine; 340 bool lastLineAligned; 341 int firstCol; 342 343 // Text handling 344 int charWidth_; 345 int charHeight_; 346 347 // Popup menu 348 QMenu* popupMenu_; 349 QAction* copyAction_; 350 QAction* findNextAction_; 351 QAction* findPreviousAction_; 352 QAction* addToSearchAction_; 353 354 // Pointer to the CrawlerWidget's QFP object 355 const QuickFindPattern* const quickFindPattern_; 356 // Our own QuickFind object 357 QuickFind quickFind_; 358 359 #ifdef GLOGG_PERF_MEASURE_FPS 360 // Performance measurement 361 PerfCounter perfCounter_; 362 #endif 363 364 // Vertical offset (in pixels) at which the first line of text is written 365 int drawingTopOffset_ = 0; 366 367 // Cache pixmap and associated info 368 struct TextAreaCache { 369 QPixmap pixmap_; 370 bool invalid_; 371 int first_line_; 372 int last_line_; 373 int first_column_; 374 }; 375 struct PullToFollowCache { 376 QPixmap pixmap_; 377 int nb_columns_; 378 }; 379 TextAreaCache textAreaCache_ = { {}, true, 0, 0, 0 }; 380 PullToFollowCache pullToFollowCache_ = { {}, 0 }; 381 382 LineNumber getNbVisibleLines() const; 383 int getNbVisibleCols() const; 384 QPoint convertCoordToFilePos( const QPoint& pos ) const; 385 int convertCoordToLine( int yPos ) const; 386 int convertCoordToColumn( int xPos ) const; 387 void displayLine( LineNumber line ); 388 void moveSelection( int y ); 389 void jumpToStartOfLine(); 390 void jumpToEndOfLine(); 391 void jumpToRightOfScreen(); 392 void jumpToTop(); 393 void jumpToBottom(); 394 void selectWordAtPosition( const QPoint& pos ); 395 396 void createMenu(); 397 398 void considerMouseHovering( int x_pos, int y_pos ); 399 400 // Search functions (for n/N) 401 void searchUsingFunction( qint64 (QuickFind::*search_function)() ); 402 403 void updateScrollBars(); 404 405 void drawTextArea( QPaintDevice* paint_device, int32_t delta_y ); 406 QPixmap drawPullToFollowBar( int width, float pixel_ratio ); 407 408 void disableFollow(); 409 410 // Utils functions 411 bool isCharWord( char c ); 412 void updateGlobalSelection(); 413 }; 414 415 #endif 416