1 /* 2 * Copyright (C) 2009, 2010, 2011, 2012, 2013 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 signals: 207 // Sent when a new line has been selected by the user. 208 void newSelection(int line); 209 // Sent up to the MainWindow to enable/disable the follow mode 210 void followModeChanged( bool enabled ); 211 // Sent when the view wants the QuickFind widget pattern to change. 212 void changeQuickFind( const QString& newPattern, 213 QuickFindMux::QFDirection newDirection ); 214 // Sent up when the current line number is updated 215 void updateLineNumber( int line ); 216 // Sent up when quickFind wants to show a message to the user. 217 void notifyQuickFind( const QFNotification& message ); 218 // Sent up when quickFind wants to clear the notification. 219 void clearQuickFindNotification(); 220 // Sent when the view ask for a line to be marked 221 // (click in the left margin). 222 void markLine( qint64 line ); 223 // Sent up when the user wants to add the selection to the search 224 void addToSearch( const QString& selection ); 225 // Sent up when the mouse is hovered over a line's margin 226 void mouseHoveredOverLine( qint64 line ); 227 // Sent up when the mouse leaves a line's margin 228 void mouseLeftHoveringZone(); 229 // Sent up for view initiated quickfind searches 230 void searchNext(); 231 void searchPrevious(); 232 // Sent up when the user has moved within the view 233 void activity(); 234 235 public slots: 236 // Makes the widget select and display the passed line. 237 // Scrolling as necessary 238 void selectAndDisplayLine( int line ); 239 240 // Use the current QFP to go and select the next match. 241 virtual void searchForward(); 242 // Use the current QFP to go and select the previous match. 243 virtual void searchBackward(); 244 245 // Use the current QFP to go and select the next match (incremental) 246 virtual void incrementallySearchForward(); 247 // Use the current QFP to go and select the previous match (incremental) 248 virtual void incrementallySearchBackward(); 249 // Stop the current incremental search (typically when user press return) 250 virtual void incrementalSearchStop(); 251 // Abort the current incremental search (typically when user press esc) 252 virtual void incrementalSearchAbort(); 253 254 // Signals the follow mode has been enabled. 255 void followSet( bool checked ); 256 257 // Signal the on/off status of the overview has been changed. 258 void refreshOverview(); 259 260 // Make the view jump to the specified line, regardless of weither it 261 // is on the screen or not. 262 // (does NOT emit followDisabled() ) 263 void jumpToLine( int line ); 264 265 // Configure the setting of whether to show line number margin 266 void setLineNumbersVisible( bool lineNumbersVisible ); 267 268 // Force the next refresh to fully redraw the view by invalidating the cache. 269 // To be used if the data might have changed. 270 void forceRefresh(); 271 272 private slots: 273 void handlePatternUpdated(); 274 void addToSearch(); 275 void findNextSelected(); 276 void findPreviousSelected(); 277 void copy(); 278 279 private: 280 // Graphic parameters 281 static constexpr int OVERVIEW_WIDTH = 27; 282 static constexpr int HOOK_THRESHOLD = 600; 283 static constexpr int PULL_TO_FOLLOW_HOOKED_HEIGHT = 10; 284 285 // Width of the bullet zone, including decoration 286 int bulletZoneWidthPx_; 287 288 // Total size of all margins and decorations in pixels 289 int leftMarginPx_; 290 291 // Digits buffer (for numeric keyboard entry) 292 DigitsBuffer digitsBuffer_; 293 294 // Follow mode 295 bool followMode_; 296 297 // ElasticHook for follow mode 298 ElasticHook followElasticHook_; 299 300 // Whether to show line numbers or not 301 bool lineNumbersVisible_; 302 303 // Pointer to the CrawlerWidget's data set 304 const AbstractLogData* logData; 305 306 // Pointer to the Overview object 307 Overview* overview_; 308 309 // Pointer to the OverviewWidget, this class doesn't own it, 310 // but is responsible for displaying it (for purely aesthetic 311 // reasons). 312 OverviewWidget* overviewWidget_; 313 314 bool selectionStarted_; 315 // Start of the selection (characters) 316 QPoint selectionStartPos_; 317 // Current end of the selection (characters) 318 QPoint selectionCurrentEndPos_; 319 QBasicTimer autoScrollTimer_; 320 321 // Hovering state 322 // Last line that has been hoovered on, -1 if none 323 qint64 lastHoveredLine_; 324 325 // Marks (left margin click) 326 bool markingClickInitiated_; 327 qint64 markingClickLine_; 328 329 Selection selection_; 330 331 // Position of the view, those are crucial to control drawing 332 // firstLine gives the position of the view, 333 // lastLineAligned == true make the bottom of the last line aligned 334 // rather than the top of the top one. 335 LineNumber firstLine; 336 bool lastLineAligned; 337 int firstCol; 338 339 // Text handling 340 int charWidth_; 341 int charHeight_; 342 343 // Popup menu 344 QMenu* popupMenu_; 345 QAction* copyAction_; 346 QAction* findNextAction_; 347 QAction* findPreviousAction_; 348 QAction* addToSearchAction_; 349 350 // Pointer to the CrawlerWidget's QFP object 351 const QuickFindPattern* const quickFindPattern_; 352 // Our own QuickFind object 353 QuickFind quickFind_; 354 355 #ifdef GLOGG_PERF_MEASURE_FPS 356 // Performance measurement 357 PerfCounter perfCounter_; 358 #endif 359 360 // Current "pull to follow" bar height 361 int pullToFollowHeight_; 362 363 // Cache pixmap and associated info 364 struct TextAreaCache { 365 QPixmap pixmap_; 366 bool invalid_; 367 int first_line_; 368 int last_line_; 369 int first_column_; 370 }; 371 struct PullToFollowCache { 372 QPixmap pixmap_; 373 int nb_columns_; 374 }; 375 TextAreaCache textAreaCache_ = { {}, true, 0, 0, 0 }; 376 PullToFollowCache pullToFollowCache_ = { {}, 0 }; 377 378 LineNumber getNbVisibleLines() const; 379 int getNbVisibleCols() const; 380 QPoint convertCoordToFilePos( const QPoint& pos ) const; 381 int convertCoordToLine( int yPos ) const; 382 int convertCoordToColumn( int xPos ) const; 383 void displayLine( LineNumber line ); 384 void moveSelection( int y ); 385 void jumpToStartOfLine(); 386 void jumpToEndOfLine(); 387 void jumpToRightOfScreen(); 388 void jumpToTop(); 389 void jumpToBottom(); 390 void selectWordAtPosition( const QPoint& pos ); 391 392 void createMenu(); 393 394 void considerMouseHovering( int x_pos, int y_pos ); 395 396 // Search functions (for n/N) 397 void searchUsingFunction( qint64 (QuickFind::*search_function)() ); 398 399 void updateScrollBars(); 400 401 void drawTextArea( QPaintDevice* paint_device, int32_t delta_y ); 402 QPixmap drawPullToFollowBar( int width, float pixel_ratio ); 403 404 void disableFollow(); 405 406 // Utils functions 407 bool isCharWord( char c ); 408 void updateGlobalSelection(); 409 }; 410 411 #endif 412