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 start()52 int start() const { return start_; } end()53 int end() const { return end_; } type()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: LineDrawer(const QColor & back_color)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 Chunk(int start,int length,QColor fore,QColor back)97 Chunk( int start, int length, QColor fore, QColor back ) 98 : start_( start ), length_( length ), 99 foreColor_ ( fore ), backColor_ ( back ) { }; 100 101 // Accessors start()102 int start() const { return start_; } length()103 int length() const { return length_; } foreColor()104 const QColor& foreColor() const { return foreColor_; } backColor()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 isFollowEnabled()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 getOverview()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 // Sent up when the user want to exit this view 239 // (switch to the next one) 240 void exitView(); 241 242 public slots: 243 // Makes the widget select and display the passed line. 244 // Scrolling as necessary 245 void selectAndDisplayLine( int line ); 246 247 // Use the current QFP to go and select the next match. 248 virtual void searchForward(); 249 // Use the current QFP to go and select the previous match. 250 virtual void searchBackward(); 251 252 // Use the current QFP to go and select the next match (incremental) 253 virtual void incrementallySearchForward(); 254 // Use the current QFP to go and select the previous match (incremental) 255 virtual void incrementallySearchBackward(); 256 // Stop the current incremental search (typically when user press return) 257 virtual void incrementalSearchStop(); 258 // Abort the current incremental search (typically when user press esc) 259 virtual void incrementalSearchAbort(); 260 261 // Signals the follow mode has been enabled. 262 void followSet( bool checked ); 263 264 // Signal the on/off status of the overview has been changed. 265 void refreshOverview(); 266 267 // Make the view jump to the specified line, regardless of weither it 268 // is on the screen or not. 269 // (does NOT emit followDisabled() ) 270 void jumpToLine( int line ); 271 272 // Configure the setting of whether to show line number margin 273 void setLineNumbersVisible( bool lineNumbersVisible ); 274 275 // Force the next refresh to fully redraw the view by invalidating the cache. 276 // To be used if the data might have changed. 277 void forceRefresh(); 278 279 private slots: 280 void handlePatternUpdated(); 281 void addToSearch(); 282 void findNextSelected(); 283 void findPreviousSelected(); 284 void copy(); 285 286 private: 287 // Graphic parameters 288 static constexpr int OVERVIEW_WIDTH = 27; 289 static constexpr int HOOK_THRESHOLD = 600; 290 static constexpr int PULL_TO_FOLLOW_HOOKED_HEIGHT = 10; 291 292 // Width of the bullet zone, including decoration 293 int bulletZoneWidthPx_; 294 295 // Total size of all margins and decorations in pixels 296 int leftMarginPx_; 297 298 // Digits buffer (for numeric keyboard entry) 299 DigitsBuffer digitsBuffer_; 300 301 // Follow mode 302 bool followMode_; 303 304 // ElasticHook for follow mode 305 ElasticHook followElasticHook_; 306 307 // Whether to show line numbers or not 308 bool lineNumbersVisible_; 309 310 // Pointer to the CrawlerWidget's data set 311 const AbstractLogData* logData; 312 313 // Pointer to the Overview object 314 Overview* overview_; 315 316 // Pointer to the OverviewWidget, this class doesn't own it, 317 // but is responsible for displaying it (for purely aesthetic 318 // reasons). 319 OverviewWidget* overviewWidget_; 320 321 bool selectionStarted_; 322 // Start of the selection (characters) 323 QPoint selectionStartPos_; 324 // Current end of the selection (characters) 325 QPoint selectionCurrentEndPos_; 326 QBasicTimer autoScrollTimer_; 327 328 // Hovering state 329 // Last line that has been hoovered on, -1 if none 330 qint64 lastHoveredLine_; 331 332 // Marks (left margin click) 333 bool markingClickInitiated_; 334 qint64 markingClickLine_; 335 336 Selection selection_; 337 338 // Position of the view, those are crucial to control drawing 339 // firstLine gives the position of the view, 340 // lastLineAligned == true make the bottom of the last line aligned 341 // rather than the top of the top one. 342 LineNumber firstLine; 343 bool lastLineAligned; 344 int firstCol; 345 346 // Text handling 347 int charWidth_; 348 int charHeight_; 349 350 // Popup menu 351 QMenu* popupMenu_; 352 QAction* copyAction_; 353 QAction* findNextAction_; 354 QAction* findPreviousAction_; 355 QAction* addToSearchAction_; 356 357 // Pointer to the CrawlerWidget's QFP object 358 const QuickFindPattern* const quickFindPattern_; 359 // Our own QuickFind object 360 QuickFind quickFind_; 361 362 #ifdef GLOGG_PERF_MEASURE_FPS 363 // Performance measurement 364 PerfCounter perfCounter_; 365 #endif 366 367 // Vertical offset (in pixels) at which the first line of text is written 368 int drawingTopOffset_ = 0; 369 370 // Cache pixmap and associated info 371 struct TextAreaCache { 372 QPixmap pixmap_; 373 bool invalid_; 374 int first_line_; 375 int last_line_; 376 int first_column_; 377 }; 378 struct PullToFollowCache { 379 QPixmap pixmap_; 380 int nb_columns_; 381 }; 382 TextAreaCache textAreaCache_ = { {}, true, 0, 0, 0 }; 383 PullToFollowCache pullToFollowCache_ = { {}, 0 }; 384 385 LineNumber getNbVisibleLines() const; 386 int getNbVisibleCols() const; 387 QPoint convertCoordToFilePos( const QPoint& pos ) const; 388 int convertCoordToLine( int yPos ) const; 389 int convertCoordToColumn( int xPos ) const; 390 void displayLine( LineNumber line ); 391 void moveSelection( int y ); 392 void jumpToStartOfLine(); 393 void jumpToEndOfLine(); 394 void jumpToRightOfScreen(); 395 void jumpToTop(); 396 void jumpToBottom(); 397 void selectWordAtPosition( const QPoint& pos ); 398 399 void createMenu(); 400 401 void considerMouseHovering( int x_pos, int y_pos ); 402 403 // Search functions (for n/N) 404 void searchUsingFunction( qint64 (QuickFind::*search_function)() ); 405 406 void updateScrollBars(); 407 408 void drawTextArea( QPaintDevice* paint_device, int32_t delta_y ); 409 QPixmap drawPullToFollowBar( int width, float pixel_ratio ); 410 411 void disableFollow(); 412 413 // Utils functions 414 bool isCharWord( char c ); 415 void updateGlobalSelection(); 416 }; 417 418 #endif 419