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