1*bb02e0acSNicolas Bonnefon /* 2*bb02e0acSNicolas Bonnefon * Copyright (C) 2009, 2010, 2011, 2013 Nicolas Bonnefon and other contributors 3*bb02e0acSNicolas Bonnefon * 4*bb02e0acSNicolas Bonnefon * This file is part of glogg. 5*bb02e0acSNicolas Bonnefon * 6*bb02e0acSNicolas Bonnefon * glogg is free software: you can redistribute it and/or modify 7*bb02e0acSNicolas Bonnefon * it under the terms of the GNU General Public License as published by 8*bb02e0acSNicolas Bonnefon * the Free Software Foundation, either version 3 of the License, or 9*bb02e0acSNicolas Bonnefon * (at your option) any later version. 10*bb02e0acSNicolas Bonnefon * 11*bb02e0acSNicolas Bonnefon * glogg is distributed in the hope that it will be useful, 12*bb02e0acSNicolas Bonnefon * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*bb02e0acSNicolas Bonnefon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*bb02e0acSNicolas Bonnefon * GNU General Public License for more details. 15*bb02e0acSNicolas Bonnefon * 16*bb02e0acSNicolas Bonnefon * You should have received a copy of the GNU General Public License 17*bb02e0acSNicolas Bonnefon * along with glogg. If not, see <http://www.gnu.org/licenses/>. 18*bb02e0acSNicolas Bonnefon */ 19*bb02e0acSNicolas Bonnefon 20*bb02e0acSNicolas Bonnefon // This file implements MainWindow. It is responsible for creating and 21*bb02e0acSNicolas Bonnefon // managing the menus, the toolbar, and the CrawlerWidget. It also 22*bb02e0acSNicolas Bonnefon // load/save the settings on opening/closing of the app 23*bb02e0acSNicolas Bonnefon 24*bb02e0acSNicolas Bonnefon #include <iostream> 25*bb02e0acSNicolas Bonnefon #include <QtGui> 26*bb02e0acSNicolas Bonnefon 27*bb02e0acSNicolas Bonnefon #include "log.h" 28*bb02e0acSNicolas Bonnefon 29*bb02e0acSNicolas Bonnefon #include "mainwindow.h" 30*bb02e0acSNicolas Bonnefon 31*bb02e0acSNicolas Bonnefon #include "sessioninfo.h" 32*bb02e0acSNicolas Bonnefon #include "recentfiles.h" 33*bb02e0acSNicolas Bonnefon #include "crawlerwidget.h" 34*bb02e0acSNicolas Bonnefon #include "filtersdialog.h" 35*bb02e0acSNicolas Bonnefon #include "optionsdialog.h" 36*bb02e0acSNicolas Bonnefon #include "persistentinfo.h" 37*bb02e0acSNicolas Bonnefon #include "savedsearches.h" 38*bb02e0acSNicolas Bonnefon #include "menuactiontooltipbehavior.h" 39*bb02e0acSNicolas Bonnefon 40*bb02e0acSNicolas Bonnefon MainWindow::MainWindow() : 41*bb02e0acSNicolas Bonnefon recentFiles( Persistent<RecentFiles>( "recentFiles" ) ), mainIcon_() 42*bb02e0acSNicolas Bonnefon { 43*bb02e0acSNicolas Bonnefon createActions(); 44*bb02e0acSNicolas Bonnefon createMenus(); 45*bb02e0acSNicolas Bonnefon // createContextMenu(); 46*bb02e0acSNicolas Bonnefon createToolBars(); 47*bb02e0acSNicolas Bonnefon // createStatusBar(); 48*bb02e0acSNicolas Bonnefon createCrawler(); 49*bb02e0acSNicolas Bonnefon 50*bb02e0acSNicolas Bonnefon setAcceptDrops( true ); 51*bb02e0acSNicolas Bonnefon 52*bb02e0acSNicolas Bonnefon // Default geometry 53*bb02e0acSNicolas Bonnefon const QRect geometry = QApplication::desktop()->availableGeometry( this ); 54*bb02e0acSNicolas Bonnefon setGeometry( geometry.x() + 20, geometry.y() + 40, 55*bb02e0acSNicolas Bonnefon geometry.width() - 140, geometry.height() - 140 ); 56*bb02e0acSNicolas Bonnefon 57*bb02e0acSNicolas Bonnefon // Send actions to the crawlerwidget 58*bb02e0acSNicolas Bonnefon connect( this, SIGNAL( followSet( bool ) ), 59*bb02e0acSNicolas Bonnefon crawlerWidget, SIGNAL( followSet( bool ) ) ); 60*bb02e0acSNicolas Bonnefon connect( this, SIGNAL( optionsChanged() ), 61*bb02e0acSNicolas Bonnefon crawlerWidget, SLOT( applyConfiguration() ) ); 62*bb02e0acSNicolas Bonnefon 63*bb02e0acSNicolas Bonnefon // Actions from the CrawlerWidget 64*bb02e0acSNicolas Bonnefon connect( crawlerWidget, SIGNAL( followDisabled() ), 65*bb02e0acSNicolas Bonnefon this, SLOT( disableFollow() ) ); 66*bb02e0acSNicolas Bonnefon connect( crawlerWidget, SIGNAL( updateLineNumber( int ) ), 67*bb02e0acSNicolas Bonnefon this, SLOT( lineNumberHandler( int ) ) ); 68*bb02e0acSNicolas Bonnefon 69*bb02e0acSNicolas Bonnefon readSettings(); 70*bb02e0acSNicolas Bonnefon emit optionsChanged(); 71*bb02e0acSNicolas Bonnefon 72*bb02e0acSNicolas Bonnefon // We start with the empty file 73*bb02e0acSNicolas Bonnefon setCurrentFile( "" ); 74*bb02e0acSNicolas Bonnefon 75*bb02e0acSNicolas Bonnefon mainIcon_.addFile( ":/images/hicolor/16x16/glogg.png" ); 76*bb02e0acSNicolas Bonnefon mainIcon_.addFile( ":/images/hicolor/24x24/glogg.png" ); 77*bb02e0acSNicolas Bonnefon mainIcon_.addFile( ":/images/hicolor/32x32/glogg.png" ); 78*bb02e0acSNicolas Bonnefon mainIcon_.addFile( ":/images/hicolor/48x48/glogg.png" ); 79*bb02e0acSNicolas Bonnefon 80*bb02e0acSNicolas Bonnefon // Register for progress status bar 81*bb02e0acSNicolas Bonnefon connect( crawlerWidget, SIGNAL( loadingProgressed( int ) ), 82*bb02e0acSNicolas Bonnefon this, SLOT( updateLoadingProgress( int ) ) ); 83*bb02e0acSNicolas Bonnefon connect( crawlerWidget, SIGNAL( loadingFinished( bool ) ), 84*bb02e0acSNicolas Bonnefon this, SLOT( displayNormalStatus( bool ) ) ); 85*bb02e0acSNicolas Bonnefon 86*bb02e0acSNicolas Bonnefon setWindowIcon( mainIcon_ ); 87*bb02e0acSNicolas Bonnefon setCentralWidget(crawlerWidget); 88*bb02e0acSNicolas Bonnefon } 89*bb02e0acSNicolas Bonnefon 90*bb02e0acSNicolas Bonnefon void MainWindow::loadInitialFile( QString fileName ) 91*bb02e0acSNicolas Bonnefon { 92*bb02e0acSNicolas Bonnefon LOG(logDEBUG) << "loadInitialFile"; 93*bb02e0acSNicolas Bonnefon 94*bb02e0acSNicolas Bonnefon // Is there a file passed as argument? 95*bb02e0acSNicolas Bonnefon if ( !fileName.isEmpty() ) 96*bb02e0acSNicolas Bonnefon loadFile( fileName ); 97*bb02e0acSNicolas Bonnefon else if ( !previousFile.isEmpty() ) 98*bb02e0acSNicolas Bonnefon loadFile( previousFile ); 99*bb02e0acSNicolas Bonnefon } 100*bb02e0acSNicolas Bonnefon 101*bb02e0acSNicolas Bonnefon // 102*bb02e0acSNicolas Bonnefon // Private functions 103*bb02e0acSNicolas Bonnefon // 104*bb02e0acSNicolas Bonnefon 105*bb02e0acSNicolas Bonnefon void MainWindow::createCrawler() 106*bb02e0acSNicolas Bonnefon { 107*bb02e0acSNicolas Bonnefon // First get the global search history 108*bb02e0acSNicolas Bonnefon savedSearches = &(Persistent<SavedSearches>( "savedSearches" )); 109*bb02e0acSNicolas Bonnefon 110*bb02e0acSNicolas Bonnefon crawlerWidget = new CrawlerWidget( savedSearches ); 111*bb02e0acSNicolas Bonnefon } 112*bb02e0acSNicolas Bonnefon 113*bb02e0acSNicolas Bonnefon // Menu actions 114*bb02e0acSNicolas Bonnefon void MainWindow::createActions() 115*bb02e0acSNicolas Bonnefon { 116*bb02e0acSNicolas Bonnefon Configuration& config = Persistent<Configuration>( "settings" ); 117*bb02e0acSNicolas Bonnefon 118*bb02e0acSNicolas Bonnefon openAction = new QAction(tr("&Open..."), this); 119*bb02e0acSNicolas Bonnefon openAction->setShortcut(QKeySequence::Open); 120*bb02e0acSNicolas Bonnefon openAction->setIcon( QIcon(":/images/open16.png") ); 121*bb02e0acSNicolas Bonnefon openAction->setStatusTip(tr("Open a file")); 122*bb02e0acSNicolas Bonnefon connect(openAction, SIGNAL(triggered()), this, SLOT(open())); 123*bb02e0acSNicolas Bonnefon 124*bb02e0acSNicolas Bonnefon // Recent files 125*bb02e0acSNicolas Bonnefon for (int i = 0; i < MaxRecentFiles; ++i) { 126*bb02e0acSNicolas Bonnefon recentFileActions[i] = new QAction(this); 127*bb02e0acSNicolas Bonnefon recentFileActions[i]->setVisible(false); 128*bb02e0acSNicolas Bonnefon connect(recentFileActions[i], SIGNAL(triggered()), 129*bb02e0acSNicolas Bonnefon this, SLOT(openRecentFile())); 130*bb02e0acSNicolas Bonnefon } 131*bb02e0acSNicolas Bonnefon 132*bb02e0acSNicolas Bonnefon exitAction = new QAction(tr("E&xit"), this); 133*bb02e0acSNicolas Bonnefon exitAction->setShortcut(tr("Ctrl+Q")); 134*bb02e0acSNicolas Bonnefon exitAction->setStatusTip(tr("Exit the application")); 135*bb02e0acSNicolas Bonnefon connect( exitAction, SIGNAL(triggered()), this, SLOT(close()) ); 136*bb02e0acSNicolas Bonnefon 137*bb02e0acSNicolas Bonnefon copyAction = new QAction(tr("&Copy"), this); 138*bb02e0acSNicolas Bonnefon copyAction->setShortcut(QKeySequence::Copy); 139*bb02e0acSNicolas Bonnefon copyAction->setStatusTip(tr("Copy the selection")); 140*bb02e0acSNicolas Bonnefon connect( copyAction, SIGNAL(triggered()), this, SLOT(copy()) ); 141*bb02e0acSNicolas Bonnefon 142*bb02e0acSNicolas Bonnefon selectAllAction = new QAction(tr("Select &All"), this); 143*bb02e0acSNicolas Bonnefon selectAllAction->setShortcut(tr("Ctrl+A")); 144*bb02e0acSNicolas Bonnefon selectAllAction->setStatusTip(tr("Select all the text")); 145*bb02e0acSNicolas Bonnefon connect( selectAllAction, SIGNAL(triggered()), 146*bb02e0acSNicolas Bonnefon this, SLOT( selectAll() ) ); 147*bb02e0acSNicolas Bonnefon 148*bb02e0acSNicolas Bonnefon findAction = new QAction(tr("&Find..."), this); 149*bb02e0acSNicolas Bonnefon findAction->setShortcut(QKeySequence::Find); 150*bb02e0acSNicolas Bonnefon findAction->setStatusTip(tr("Find the text")); 151*bb02e0acSNicolas Bonnefon connect( findAction, SIGNAL(triggered()), 152*bb02e0acSNicolas Bonnefon this, SLOT( find() ) ); 153*bb02e0acSNicolas Bonnefon 154*bb02e0acSNicolas Bonnefon overviewVisibleAction = new QAction( tr("Matches &overview"), this ); 155*bb02e0acSNicolas Bonnefon overviewVisibleAction->setCheckable( true ); 156*bb02e0acSNicolas Bonnefon overviewVisibleAction->setChecked( config.isOverviewVisible() ); 157*bb02e0acSNicolas Bonnefon connect( overviewVisibleAction, SIGNAL( toggled( bool ) ), 158*bb02e0acSNicolas Bonnefon this, SLOT( toggleOverviewVisibility( bool )) ); 159*bb02e0acSNicolas Bonnefon 160*bb02e0acSNicolas Bonnefon lineNumbersVisibleInMainAction = 161*bb02e0acSNicolas Bonnefon new QAction( tr("Line &numbers in main view"), this ); 162*bb02e0acSNicolas Bonnefon lineNumbersVisibleInMainAction->setCheckable( true ); 163*bb02e0acSNicolas Bonnefon lineNumbersVisibleInMainAction->setChecked( config.mainLineNumbersVisible() ); 164*bb02e0acSNicolas Bonnefon connect( lineNumbersVisibleInMainAction, SIGNAL( toggled( bool ) ), 165*bb02e0acSNicolas Bonnefon this, SLOT( toggleMainLineNumbersVisibility( bool )) ); 166*bb02e0acSNicolas Bonnefon 167*bb02e0acSNicolas Bonnefon lineNumbersVisibleInFilteredAction = 168*bb02e0acSNicolas Bonnefon new QAction( tr("Line &numbers in filtered view"), this ); 169*bb02e0acSNicolas Bonnefon lineNumbersVisibleInFilteredAction->setCheckable( true ); 170*bb02e0acSNicolas Bonnefon lineNumbersVisibleInFilteredAction->setChecked( config.filteredLineNumbersVisible() ); 171*bb02e0acSNicolas Bonnefon connect( lineNumbersVisibleInFilteredAction, SIGNAL( toggled( bool ) ), 172*bb02e0acSNicolas Bonnefon this, SLOT( toggleFilteredLineNumbersVisibility( bool )) ); 173*bb02e0acSNicolas Bonnefon 174*bb02e0acSNicolas Bonnefon followAction = new QAction( tr("&Follow File"), this ); 175*bb02e0acSNicolas Bonnefon followAction->setShortcut(Qt::Key_F); 176*bb02e0acSNicolas Bonnefon followAction->setCheckable(true); 177*bb02e0acSNicolas Bonnefon connect( followAction, SIGNAL(toggled( bool )), 178*bb02e0acSNicolas Bonnefon this, SIGNAL(followSet( bool )) ); 179*bb02e0acSNicolas Bonnefon 180*bb02e0acSNicolas Bonnefon reloadAction = new QAction( tr("&Reload"), this ); 181*bb02e0acSNicolas Bonnefon reloadAction->setShortcut(QKeySequence::Refresh); 182*bb02e0acSNicolas Bonnefon reloadAction->setIcon( QIcon(":/images/reload16.png") ); 183*bb02e0acSNicolas Bonnefon connect( reloadAction, SIGNAL(triggered()), this, SLOT(reload()) ); 184*bb02e0acSNicolas Bonnefon 185*bb02e0acSNicolas Bonnefon stopAction = new QAction( tr("&Stop"), this ); 186*bb02e0acSNicolas Bonnefon stopAction->setIcon( QIcon(":/images/stop16.png") ); 187*bb02e0acSNicolas Bonnefon stopAction->setEnabled( false ); 188*bb02e0acSNicolas Bonnefon connect( stopAction, SIGNAL(triggered()), this, SLOT(stop()) ); 189*bb02e0acSNicolas Bonnefon 190*bb02e0acSNicolas Bonnefon filtersAction = new QAction(tr("&Filters..."), this); 191*bb02e0acSNicolas Bonnefon filtersAction->setStatusTip(tr("Show the Filters box")); 192*bb02e0acSNicolas Bonnefon connect( filtersAction, SIGNAL(triggered()), this, SLOT(filters()) ); 193*bb02e0acSNicolas Bonnefon 194*bb02e0acSNicolas Bonnefon optionsAction = new QAction(tr("&Options..."), this); 195*bb02e0acSNicolas Bonnefon optionsAction->setStatusTip(tr("Show the Options box")); 196*bb02e0acSNicolas Bonnefon connect( optionsAction, SIGNAL(triggered()), this, SLOT(options()) ); 197*bb02e0acSNicolas Bonnefon 198*bb02e0acSNicolas Bonnefon aboutAction = new QAction(tr("&About"), this); 199*bb02e0acSNicolas Bonnefon aboutAction->setStatusTip(tr("Show the About box")); 200*bb02e0acSNicolas Bonnefon connect( aboutAction, SIGNAL(triggered()), this, SLOT(about()) ); 201*bb02e0acSNicolas Bonnefon 202*bb02e0acSNicolas Bonnefon aboutQtAction = new QAction(tr("About &Qt"), this); 203*bb02e0acSNicolas Bonnefon aboutAction->setStatusTip(tr("Show the Qt library's About box")); 204*bb02e0acSNicolas Bonnefon connect( aboutQtAction, SIGNAL(triggered()), this, SLOT(aboutQt()) ); 205*bb02e0acSNicolas Bonnefon } 206*bb02e0acSNicolas Bonnefon 207*bb02e0acSNicolas Bonnefon void MainWindow::createMenus() 208*bb02e0acSNicolas Bonnefon { 209*bb02e0acSNicolas Bonnefon fileMenu = menuBar()->addMenu( tr("&File") ); 210*bb02e0acSNicolas Bonnefon fileMenu->addAction( openAction ); 211*bb02e0acSNicolas Bonnefon fileMenu->addSeparator(); 212*bb02e0acSNicolas Bonnefon for (int i = 0; i < MaxRecentFiles; ++i) { 213*bb02e0acSNicolas Bonnefon fileMenu->addAction( recentFileActions[i] ); 214*bb02e0acSNicolas Bonnefon recentFileActionBehaviors[i] = 215*bb02e0acSNicolas Bonnefon new MenuActionToolTipBehavior(recentFileActions[i], fileMenu, this); 216*bb02e0acSNicolas Bonnefon } 217*bb02e0acSNicolas Bonnefon fileMenu->addSeparator(); 218*bb02e0acSNicolas Bonnefon fileMenu->addAction( exitAction ); 219*bb02e0acSNicolas Bonnefon 220*bb02e0acSNicolas Bonnefon editMenu = menuBar()->addMenu( tr("&Edit") ); 221*bb02e0acSNicolas Bonnefon editMenu->addAction( copyAction ); 222*bb02e0acSNicolas Bonnefon editMenu->addAction( selectAllAction ); 223*bb02e0acSNicolas Bonnefon editMenu->addSeparator(); 224*bb02e0acSNicolas Bonnefon editMenu->addAction( findAction ); 225*bb02e0acSNicolas Bonnefon 226*bb02e0acSNicolas Bonnefon viewMenu = menuBar()->addMenu( tr("&View") ); 227*bb02e0acSNicolas Bonnefon viewMenu->addAction( overviewVisibleAction ); 228*bb02e0acSNicolas Bonnefon viewMenu->addSeparator(); 229*bb02e0acSNicolas Bonnefon viewMenu->addAction( lineNumbersVisibleInMainAction ); 230*bb02e0acSNicolas Bonnefon viewMenu->addAction( lineNumbersVisibleInFilteredAction ); 231*bb02e0acSNicolas Bonnefon viewMenu->addSeparator(); 232*bb02e0acSNicolas Bonnefon viewMenu->addAction( followAction ); 233*bb02e0acSNicolas Bonnefon viewMenu->addSeparator(); 234*bb02e0acSNicolas Bonnefon viewMenu->addAction( reloadAction ); 235*bb02e0acSNicolas Bonnefon 236*bb02e0acSNicolas Bonnefon toolsMenu = menuBar()->addMenu( tr("&Tools") ); 237*bb02e0acSNicolas Bonnefon toolsMenu->addAction( filtersAction ); 238*bb02e0acSNicolas Bonnefon toolsMenu->addSeparator(); 239*bb02e0acSNicolas Bonnefon toolsMenu->addAction( optionsAction ); 240*bb02e0acSNicolas Bonnefon 241*bb02e0acSNicolas Bonnefon menuBar()->addSeparator(); 242*bb02e0acSNicolas Bonnefon 243*bb02e0acSNicolas Bonnefon helpMenu = menuBar()->addMenu( tr("&Help") ); 244*bb02e0acSNicolas Bonnefon helpMenu->addAction( aboutAction ); 245*bb02e0acSNicolas Bonnefon } 246*bb02e0acSNicolas Bonnefon 247*bb02e0acSNicolas Bonnefon void MainWindow::createToolBars() 248*bb02e0acSNicolas Bonnefon { 249*bb02e0acSNicolas Bonnefon infoLine = new InfoLine(); 250*bb02e0acSNicolas Bonnefon infoLine->setFrameStyle( QFrame::WinPanel | QFrame::Sunken ); 251*bb02e0acSNicolas Bonnefon infoLine->setLineWidth( 0 ); 252*bb02e0acSNicolas Bonnefon 253*bb02e0acSNicolas Bonnefon lineNbField = new QLabel( ); 254*bb02e0acSNicolas Bonnefon lineNbField->setText( "Line 0" ); 255*bb02e0acSNicolas Bonnefon lineNbField->setAlignment( Qt::AlignLeft | Qt::AlignVCenter ); 256*bb02e0acSNicolas Bonnefon lineNbField->setMinimumSize( 257*bb02e0acSNicolas Bonnefon lineNbField->fontMetrics().size( 0, "Line 0000000") ); 258*bb02e0acSNicolas Bonnefon 259*bb02e0acSNicolas Bonnefon toolBar = addToolBar( tr("&Toolbar") ); 260*bb02e0acSNicolas Bonnefon toolBar->setIconSize( QSize( 16, 16 ) ); 261*bb02e0acSNicolas Bonnefon toolBar->setMovable( false ); 262*bb02e0acSNicolas Bonnefon toolBar->addAction( openAction ); 263*bb02e0acSNicolas Bonnefon toolBar->addAction( reloadAction ); 264*bb02e0acSNicolas Bonnefon toolBar->addWidget( infoLine ); 265*bb02e0acSNicolas Bonnefon toolBar->addAction( stopAction ); 266*bb02e0acSNicolas Bonnefon toolBar->addWidget( lineNbField ); 267*bb02e0acSNicolas Bonnefon } 268*bb02e0acSNicolas Bonnefon 269*bb02e0acSNicolas Bonnefon // 270*bb02e0acSNicolas Bonnefon // Slots 271*bb02e0acSNicolas Bonnefon // 272*bb02e0acSNicolas Bonnefon 273*bb02e0acSNicolas Bonnefon // Opens the file selection dialog to select a new log file 274*bb02e0acSNicolas Bonnefon void MainWindow::open() 275*bb02e0acSNicolas Bonnefon { 276*bb02e0acSNicolas Bonnefon QString defaultDir = "."; 277*bb02e0acSNicolas Bonnefon 278*bb02e0acSNicolas Bonnefon // Default to the path of the current file if there is one 279*bb02e0acSNicolas Bonnefon if ( !currentFile.isEmpty() ) { 280*bb02e0acSNicolas Bonnefon QFileInfo fileInfo = QFileInfo( currentFile ); 281*bb02e0acSNicolas Bonnefon defaultDir = fileInfo.path(); 282*bb02e0acSNicolas Bonnefon } 283*bb02e0acSNicolas Bonnefon 284*bb02e0acSNicolas Bonnefon QString fileName = QFileDialog::getOpenFileName(this, 285*bb02e0acSNicolas Bonnefon tr("Open file"), defaultDir, tr("All files (*)")); 286*bb02e0acSNicolas Bonnefon if (!fileName.isEmpty()) 287*bb02e0acSNicolas Bonnefon loadFile(fileName); 288*bb02e0acSNicolas Bonnefon } 289*bb02e0acSNicolas Bonnefon 290*bb02e0acSNicolas Bonnefon // Opens a log file from the recent files list 291*bb02e0acSNicolas Bonnefon void MainWindow::openRecentFile() 292*bb02e0acSNicolas Bonnefon { 293*bb02e0acSNicolas Bonnefon QAction* action = qobject_cast<QAction*>(sender()); 294*bb02e0acSNicolas Bonnefon if (action) 295*bb02e0acSNicolas Bonnefon loadFile(action->data().toString()); 296*bb02e0acSNicolas Bonnefon } 297*bb02e0acSNicolas Bonnefon 298*bb02e0acSNicolas Bonnefon // Select all the text in the currently selected view 299*bb02e0acSNicolas Bonnefon void MainWindow::selectAll() 300*bb02e0acSNicolas Bonnefon { 301*bb02e0acSNicolas Bonnefon crawlerWidget->selectAll(); 302*bb02e0acSNicolas Bonnefon } 303*bb02e0acSNicolas Bonnefon 304*bb02e0acSNicolas Bonnefon // Copy the currently selected line into the clipboard 305*bb02e0acSNicolas Bonnefon void MainWindow::copy() 306*bb02e0acSNicolas Bonnefon { 307*bb02e0acSNicolas Bonnefon static QClipboard* clipboard = QApplication::clipboard(); 308*bb02e0acSNicolas Bonnefon 309*bb02e0acSNicolas Bonnefon clipboard->setText( crawlerWidget->getSelectedText() ); 310*bb02e0acSNicolas Bonnefon 311*bb02e0acSNicolas Bonnefon // Put it in the global selection as well (X11 only) 312*bb02e0acSNicolas Bonnefon clipboard->setText( crawlerWidget->getSelectedText(), 313*bb02e0acSNicolas Bonnefon QClipboard::Selection ); 314*bb02e0acSNicolas Bonnefon } 315*bb02e0acSNicolas Bonnefon 316*bb02e0acSNicolas Bonnefon // Display the QuickFind bar 317*bb02e0acSNicolas Bonnefon void MainWindow::find() 318*bb02e0acSNicolas Bonnefon { 319*bb02e0acSNicolas Bonnefon crawlerWidget->displayQuickFindBar( QuickFindMux::Forward ); 320*bb02e0acSNicolas Bonnefon } 321*bb02e0acSNicolas Bonnefon 322*bb02e0acSNicolas Bonnefon // Reload the current log file 323*bb02e0acSNicolas Bonnefon void MainWindow::reload() 324*bb02e0acSNicolas Bonnefon { 325*bb02e0acSNicolas Bonnefon if ( !currentFile.isEmpty() ) 326*bb02e0acSNicolas Bonnefon loadFile( currentFile ); 327*bb02e0acSNicolas Bonnefon } 328*bb02e0acSNicolas Bonnefon 329*bb02e0acSNicolas Bonnefon // Stop the loading operation 330*bb02e0acSNicolas Bonnefon void MainWindow::stop() 331*bb02e0acSNicolas Bonnefon { 332*bb02e0acSNicolas Bonnefon crawlerWidget->stopLoading(); 333*bb02e0acSNicolas Bonnefon } 334*bb02e0acSNicolas Bonnefon 335*bb02e0acSNicolas Bonnefon // Opens the 'Filters' dialog box 336*bb02e0acSNicolas Bonnefon void MainWindow::filters() 337*bb02e0acSNicolas Bonnefon { 338*bb02e0acSNicolas Bonnefon FiltersDialog dialog(this); 339*bb02e0acSNicolas Bonnefon connect(&dialog, SIGNAL( optionsChanged() ), crawlerWidget, SLOT( applyConfiguration() )); 340*bb02e0acSNicolas Bonnefon dialog.exec(); 341*bb02e0acSNicolas Bonnefon } 342*bb02e0acSNicolas Bonnefon 343*bb02e0acSNicolas Bonnefon // Opens the 'Options' modal dialog box 344*bb02e0acSNicolas Bonnefon void MainWindow::options() 345*bb02e0acSNicolas Bonnefon { 346*bb02e0acSNicolas Bonnefon OptionsDialog dialog(this); 347*bb02e0acSNicolas Bonnefon connect(&dialog, SIGNAL( optionsChanged() ), crawlerWidget, SLOT( applyConfiguration() )); 348*bb02e0acSNicolas Bonnefon dialog.exec(); 349*bb02e0acSNicolas Bonnefon } 350*bb02e0acSNicolas Bonnefon 351*bb02e0acSNicolas Bonnefon // Opens the 'About' dialog box. 352*bb02e0acSNicolas Bonnefon void MainWindow::about() 353*bb02e0acSNicolas Bonnefon { 354*bb02e0acSNicolas Bonnefon QMessageBox::about(this, tr("About glogg"), 355*bb02e0acSNicolas Bonnefon tr("<h2>glogg " GLOGG_VERSION "</h2>" 356*bb02e0acSNicolas Bonnefon "<p>A fast, advanced log explorer." 357*bb02e0acSNicolas Bonnefon #ifdef GLOGG_COMMIT 358*bb02e0acSNicolas Bonnefon "<p>Built " GLOGG_DATE " from " GLOGG_COMMIT 359*bb02e0acSNicolas Bonnefon #endif 360*bb02e0acSNicolas Bonnefon "<p>Copyright © 2009, 2010, 2011, 2012, 2013 Nicolas Bonnefon and other contributors" 361*bb02e0acSNicolas Bonnefon "<p>You may modify and redistribute the program under the terms of the GPL (version 3 or later)." ) ); 362*bb02e0acSNicolas Bonnefon } 363*bb02e0acSNicolas Bonnefon 364*bb02e0acSNicolas Bonnefon // Opens the 'About Qt' dialog box. 365*bb02e0acSNicolas Bonnefon void MainWindow::aboutQt() 366*bb02e0acSNicolas Bonnefon { 367*bb02e0acSNicolas Bonnefon } 368*bb02e0acSNicolas Bonnefon 369*bb02e0acSNicolas Bonnefon void MainWindow::toggleOverviewVisibility( bool isVisible ) 370*bb02e0acSNicolas Bonnefon { 371*bb02e0acSNicolas Bonnefon Configuration& config = Persistent<Configuration>( "settings" ); 372*bb02e0acSNicolas Bonnefon config.setOverviewVisible( isVisible ); 373*bb02e0acSNicolas Bonnefon emit optionsChanged(); 374*bb02e0acSNicolas Bonnefon } 375*bb02e0acSNicolas Bonnefon 376*bb02e0acSNicolas Bonnefon void MainWindow::toggleMainLineNumbersVisibility( bool isVisible ) 377*bb02e0acSNicolas Bonnefon { 378*bb02e0acSNicolas Bonnefon Configuration& config = Persistent<Configuration>( "settings" ); 379*bb02e0acSNicolas Bonnefon config.setMainLineNumbersVisible( isVisible ); 380*bb02e0acSNicolas Bonnefon emit optionsChanged(); 381*bb02e0acSNicolas Bonnefon } 382*bb02e0acSNicolas Bonnefon 383*bb02e0acSNicolas Bonnefon void MainWindow::toggleFilteredLineNumbersVisibility( bool isVisible ) 384*bb02e0acSNicolas Bonnefon { 385*bb02e0acSNicolas Bonnefon Configuration& config = Persistent<Configuration>( "settings" ); 386*bb02e0acSNicolas Bonnefon config.setFilteredLineNumbersVisible( isVisible ); 387*bb02e0acSNicolas Bonnefon emit optionsChanged(); 388*bb02e0acSNicolas Bonnefon } 389*bb02e0acSNicolas Bonnefon 390*bb02e0acSNicolas Bonnefon void MainWindow::disableFollow() 391*bb02e0acSNicolas Bonnefon { 392*bb02e0acSNicolas Bonnefon followAction->setChecked( false ); 393*bb02e0acSNicolas Bonnefon } 394*bb02e0acSNicolas Bonnefon 395*bb02e0acSNicolas Bonnefon void MainWindow::lineNumberHandler( int line ) 396*bb02e0acSNicolas Bonnefon { 397*bb02e0acSNicolas Bonnefon // The line number received is the internal (starts at 0) 398*bb02e0acSNicolas Bonnefon lineNbField->setText( tr( "Line %1" ).arg( line + 1 ) ); 399*bb02e0acSNicolas Bonnefon } 400*bb02e0acSNicolas Bonnefon 401*bb02e0acSNicolas Bonnefon void MainWindow::updateLoadingProgress( int progress ) 402*bb02e0acSNicolas Bonnefon { 403*bb02e0acSNicolas Bonnefon LOG(logDEBUG) << "Loading progress: " << progress; 404*bb02e0acSNicolas Bonnefon 405*bb02e0acSNicolas Bonnefon // We ignore 0% and 100% to avoid a flash when the file (or update) 406*bb02e0acSNicolas Bonnefon // is very short. 407*bb02e0acSNicolas Bonnefon if ( progress > 0 && progress < 100 ) { 408*bb02e0acSNicolas Bonnefon infoLine->setText( loadingFileName + tr( " - Indexing lines... (%1 %)" ).arg( progress ) ); 409*bb02e0acSNicolas Bonnefon infoLine->displayGauge( progress ); 410*bb02e0acSNicolas Bonnefon 411*bb02e0acSNicolas Bonnefon stopAction->setEnabled( true ); 412*bb02e0acSNicolas Bonnefon } 413*bb02e0acSNicolas Bonnefon } 414*bb02e0acSNicolas Bonnefon 415*bb02e0acSNicolas Bonnefon void MainWindow::displayNormalStatus( bool success ) 416*bb02e0acSNicolas Bonnefon { 417*bb02e0acSNicolas Bonnefon QLocale defaultLocale; 418*bb02e0acSNicolas Bonnefon 419*bb02e0acSNicolas Bonnefon LOG(logDEBUG) << "displayNormalStatus"; 420*bb02e0acSNicolas Bonnefon 421*bb02e0acSNicolas Bonnefon if ( success ) 422*bb02e0acSNicolas Bonnefon setCurrentFile( loadingFileName ); 423*bb02e0acSNicolas Bonnefon 424*bb02e0acSNicolas Bonnefon qint64 fileSize; 425*bb02e0acSNicolas Bonnefon int fileNbLine; 426*bb02e0acSNicolas Bonnefon QDateTime lastModified; 427*bb02e0acSNicolas Bonnefon 428*bb02e0acSNicolas Bonnefon crawlerWidget->getFileInfo( &fileSize, &fileNbLine, &lastModified ); 429*bb02e0acSNicolas Bonnefon if ( lastModified.isValid() ) { 430*bb02e0acSNicolas Bonnefon const QString date = 431*bb02e0acSNicolas Bonnefon #if QT_VERSION > 0x040500 432*bb02e0acSNicolas Bonnefon defaultLocale.toString( lastModified, QLocale::NarrowFormat ); 433*bb02e0acSNicolas Bonnefon #else 434*bb02e0acSNicolas Bonnefon defaultLocale.toString( lastModified.date(), QLocale::ShortFormat ) 435*bb02e0acSNicolas Bonnefon .append( " " ).append( defaultLocale.toString( 436*bb02e0acSNicolas Bonnefon lastModified.time(), QLocale::ShortFormat ) ); 437*bb02e0acSNicolas Bonnefon #endif 438*bb02e0acSNicolas Bonnefon infoLine->setText( tr( "%1 (%2 - %3 lines - modified on %4)" ) 439*bb02e0acSNicolas Bonnefon .arg(currentFile).arg(readableSize(fileSize)) 440*bb02e0acSNicolas Bonnefon .arg(fileNbLine).arg( date ) ); 441*bb02e0acSNicolas Bonnefon } 442*bb02e0acSNicolas Bonnefon else { 443*bb02e0acSNicolas Bonnefon infoLine->setText( tr( "%1 (%2 - %3 lines)" ) 444*bb02e0acSNicolas Bonnefon .arg(currentFile).arg(readableSize(fileSize)) 445*bb02e0acSNicolas Bonnefon .arg(fileNbLine) ); 446*bb02e0acSNicolas Bonnefon } 447*bb02e0acSNicolas Bonnefon 448*bb02e0acSNicolas Bonnefon infoLine->hideGauge(); 449*bb02e0acSNicolas Bonnefon stopAction->setEnabled( false ); 450*bb02e0acSNicolas Bonnefon } 451*bb02e0acSNicolas Bonnefon 452*bb02e0acSNicolas Bonnefon // 453*bb02e0acSNicolas Bonnefon // Events 454*bb02e0acSNicolas Bonnefon // 455*bb02e0acSNicolas Bonnefon 456*bb02e0acSNicolas Bonnefon // Closes the application 457*bb02e0acSNicolas Bonnefon void MainWindow::closeEvent( QCloseEvent *event ) 458*bb02e0acSNicolas Bonnefon { 459*bb02e0acSNicolas Bonnefon writeSettings(); 460*bb02e0acSNicolas Bonnefon event->accept(); 461*bb02e0acSNicolas Bonnefon } 462*bb02e0acSNicolas Bonnefon 463*bb02e0acSNicolas Bonnefon // Accepts the drag event if it looks like a filename 464*bb02e0acSNicolas Bonnefon void MainWindow::dragEnterEvent( QDragEnterEvent* event ) 465*bb02e0acSNicolas Bonnefon { 466*bb02e0acSNicolas Bonnefon if ( event->mimeData()->hasFormat( "text/uri-list" ) ) 467*bb02e0acSNicolas Bonnefon event->acceptProposedAction(); 468*bb02e0acSNicolas Bonnefon } 469*bb02e0acSNicolas Bonnefon 470*bb02e0acSNicolas Bonnefon // Tries and loads the file if the URL dropped is local 471*bb02e0acSNicolas Bonnefon void MainWindow::dropEvent( QDropEvent* event ) 472*bb02e0acSNicolas Bonnefon { 473*bb02e0acSNicolas Bonnefon QList<QUrl> urls = event->mimeData()->urls(); 474*bb02e0acSNicolas Bonnefon if ( urls.isEmpty() ) 475*bb02e0acSNicolas Bonnefon return; 476*bb02e0acSNicolas Bonnefon 477*bb02e0acSNicolas Bonnefon QString fileName = urls.first().toLocalFile(); 478*bb02e0acSNicolas Bonnefon if ( fileName.isEmpty() ) 479*bb02e0acSNicolas Bonnefon return; 480*bb02e0acSNicolas Bonnefon 481*bb02e0acSNicolas Bonnefon loadFile( fileName ); 482*bb02e0acSNicolas Bonnefon } 483*bb02e0acSNicolas Bonnefon 484*bb02e0acSNicolas Bonnefon // 485*bb02e0acSNicolas Bonnefon // Private functions 486*bb02e0acSNicolas Bonnefon // 487*bb02e0acSNicolas Bonnefon 488*bb02e0acSNicolas Bonnefon // Loads the passed file into the CrawlerWidget and update the title bar. 489*bb02e0acSNicolas Bonnefon // The loading is done asynchronously. 490*bb02e0acSNicolas Bonnefon bool MainWindow::loadFile( const QString& fileName ) 491*bb02e0acSNicolas Bonnefon { 492*bb02e0acSNicolas Bonnefon LOG(logDEBUG) << "loadFile ( " << fileName.toStdString() << " )"; 493*bb02e0acSNicolas Bonnefon 494*bb02e0acSNicolas Bonnefon int topLine = 0; 495*bb02e0acSNicolas Bonnefon 496*bb02e0acSNicolas Bonnefon // If we're loading the same file, put the same line on top. 497*bb02e0acSNicolas Bonnefon if ( fileName == currentFile ) 498*bb02e0acSNicolas Bonnefon topLine = crawlerWidget->getTopLine(); 499*bb02e0acSNicolas Bonnefon 500*bb02e0acSNicolas Bonnefon // Load the file 501*bb02e0acSNicolas Bonnefon loadingFileName = fileName; 502*bb02e0acSNicolas Bonnefon if ( crawlerWidget->readFile( fileName, topLine ) ) { 503*bb02e0acSNicolas Bonnefon LOG(logDEBUG) << "Success loading file " << fileName.toStdString(); 504*bb02e0acSNicolas Bonnefon return true; 505*bb02e0acSNicolas Bonnefon } 506*bb02e0acSNicolas Bonnefon else { 507*bb02e0acSNicolas Bonnefon LOG(logWARNING) << "Cannot load file " << fileName.toStdString(); 508*bb02e0acSNicolas Bonnefon displayNormalStatus( false ); 509*bb02e0acSNicolas Bonnefon return false; 510*bb02e0acSNicolas Bonnefon } 511*bb02e0acSNicolas Bonnefon } 512*bb02e0acSNicolas Bonnefon 513*bb02e0acSNicolas Bonnefon // Strips the passed filename from its directory part. 514*bb02e0acSNicolas Bonnefon QString MainWindow::strippedName( const QString& fullFileName ) const 515*bb02e0acSNicolas Bonnefon { 516*bb02e0acSNicolas Bonnefon return QFileInfo( fullFileName ).fileName(); 517*bb02e0acSNicolas Bonnefon } 518*bb02e0acSNicolas Bonnefon 519*bb02e0acSNicolas Bonnefon // Add the filename to the recent files list and update the title bar. 520*bb02e0acSNicolas Bonnefon void MainWindow::setCurrentFile( const QString& fileName ) 521*bb02e0acSNicolas Bonnefon { 522*bb02e0acSNicolas Bonnefon // Change the current file 523*bb02e0acSNicolas Bonnefon currentFile = fileName; 524*bb02e0acSNicolas Bonnefon QString shownName = tr( "Untitled" ); 525*bb02e0acSNicolas Bonnefon if ( !currentFile.isEmpty() ) { 526*bb02e0acSNicolas Bonnefon // (reload the list first in case another glogg changed it) 527*bb02e0acSNicolas Bonnefon GetPersistentInfo().retrieve( "recentFiles" ); 528*bb02e0acSNicolas Bonnefon recentFiles.addRecent( currentFile ); 529*bb02e0acSNicolas Bonnefon GetPersistentInfo().save( "recentFiles" ); 530*bb02e0acSNicolas Bonnefon updateRecentFileActions(); 531*bb02e0acSNicolas Bonnefon shownName = strippedName( currentFile ); 532*bb02e0acSNicolas Bonnefon } 533*bb02e0acSNicolas Bonnefon 534*bb02e0acSNicolas Bonnefon setWindowTitle( 535*bb02e0acSNicolas Bonnefon tr("%1 - %2").arg(shownName).arg(tr("glogg")) 536*bb02e0acSNicolas Bonnefon #ifdef GLOGG_COMMIT 537*bb02e0acSNicolas Bonnefon + " (dev build " GLOGG_VERSION ")" 538*bb02e0acSNicolas Bonnefon #endif 539*bb02e0acSNicolas Bonnefon ); 540*bb02e0acSNicolas Bonnefon } 541*bb02e0acSNicolas Bonnefon 542*bb02e0acSNicolas Bonnefon // Updates the actions for the recent files. 543*bb02e0acSNicolas Bonnefon // Must be called after having added a new name to the list. 544*bb02e0acSNicolas Bonnefon void MainWindow::updateRecentFileActions() 545*bb02e0acSNicolas Bonnefon { 546*bb02e0acSNicolas Bonnefon QStringList recent_files = recentFiles.recentFiles(); 547*bb02e0acSNicolas Bonnefon 548*bb02e0acSNicolas Bonnefon for ( int j = 0; j < MaxRecentFiles; ++j ) { 549*bb02e0acSNicolas Bonnefon if ( j < recent_files.count() ) { 550*bb02e0acSNicolas Bonnefon QString text = tr("&%1 %2").arg(j + 1).arg(strippedName(recent_files[j])); 551*bb02e0acSNicolas Bonnefon recentFileActions[j]->setText( text ); 552*bb02e0acSNicolas Bonnefon recentFileActions[j]->setToolTip( recent_files[j] ); 553*bb02e0acSNicolas Bonnefon recentFileActions[j]->setData( recent_files[j] ); 554*bb02e0acSNicolas Bonnefon recentFileActions[j]->setVisible( true ); 555*bb02e0acSNicolas Bonnefon } 556*bb02e0acSNicolas Bonnefon else { 557*bb02e0acSNicolas Bonnefon recentFileActions[j]->setVisible( false ); 558*bb02e0acSNicolas Bonnefon } 559*bb02e0acSNicolas Bonnefon } 560*bb02e0acSNicolas Bonnefon 561*bb02e0acSNicolas Bonnefon // separatorAction->setVisible(!recentFiles.isEmpty()); 562*bb02e0acSNicolas Bonnefon } 563*bb02e0acSNicolas Bonnefon 564*bb02e0acSNicolas Bonnefon // Write settings to permanent storage 565*bb02e0acSNicolas Bonnefon void MainWindow::writeSettings() 566*bb02e0acSNicolas Bonnefon { 567*bb02e0acSNicolas Bonnefon // Save the session 568*bb02e0acSNicolas Bonnefon SessionInfo& session = Persistent<SessionInfo>( "session" ); 569*bb02e0acSNicolas Bonnefon session.setGeometry( saveGeometry() ); 570*bb02e0acSNicolas Bonnefon session.setCrawlerState( crawlerWidget->saveState() ); 571*bb02e0acSNicolas Bonnefon session.setCurrentFile( currentFile ); 572*bb02e0acSNicolas Bonnefon GetPersistentInfo().save( QString( "session" ) ); 573*bb02e0acSNicolas Bonnefon 574*bb02e0acSNicolas Bonnefon // User settings 575*bb02e0acSNicolas Bonnefon GetPersistentInfo().save( QString( "settings" ) ); 576*bb02e0acSNicolas Bonnefon } 577*bb02e0acSNicolas Bonnefon 578*bb02e0acSNicolas Bonnefon // Read settings from permanent storage 579*bb02e0acSNicolas Bonnefon void MainWindow::readSettings() 580*bb02e0acSNicolas Bonnefon { 581*bb02e0acSNicolas Bonnefon // Get and restore the session 582*bb02e0acSNicolas Bonnefon GetPersistentInfo().retrieve( QString( "session" ) ); 583*bb02e0acSNicolas Bonnefon SessionInfo session = Persistent<SessionInfo>( "session" ); 584*bb02e0acSNicolas Bonnefon restoreGeometry( session.geometry() ); 585*bb02e0acSNicolas Bonnefon crawlerWidget->restoreState( session.crawlerState() ); 586*bb02e0acSNicolas Bonnefon previousFile = session.currentFile(); 587*bb02e0acSNicolas Bonnefon 588*bb02e0acSNicolas Bonnefon // History of recent files 589*bb02e0acSNicolas Bonnefon GetPersistentInfo().retrieve( QString( "recentFiles" ) ); 590*bb02e0acSNicolas Bonnefon updateRecentFileActions(); 591*bb02e0acSNicolas Bonnefon 592*bb02e0acSNicolas Bonnefon GetPersistentInfo().retrieve( QString( "savedSearches" ) ); 593*bb02e0acSNicolas Bonnefon GetPersistentInfo().retrieve( QString( "settings" ) ); 594*bb02e0acSNicolas Bonnefon GetPersistentInfo().retrieve( QString( "filterSet" ) ); 595*bb02e0acSNicolas Bonnefon } 596*bb02e0acSNicolas Bonnefon 597*bb02e0acSNicolas Bonnefon // Returns the size in human readable format 598*bb02e0acSNicolas Bonnefon QString MainWindow::readableSize( qint64 size ) const 599*bb02e0acSNicolas Bonnefon { 600*bb02e0acSNicolas Bonnefon static const QString sizeStrs[] = { 601*bb02e0acSNicolas Bonnefon tr("B"), tr("KiB"), tr("MiB"), tr("GiB"), tr("TiB") }; 602*bb02e0acSNicolas Bonnefon 603*bb02e0acSNicolas Bonnefon QLocale defaultLocale; 604*bb02e0acSNicolas Bonnefon unsigned int i; 605*bb02e0acSNicolas Bonnefon double humanSize = size; 606*bb02e0acSNicolas Bonnefon 607*bb02e0acSNicolas Bonnefon for ( i=0; i+1 < (sizeof(sizeStrs)/sizeof(QString)) && (humanSize/1024.0) >= 1024.0; i++ ) 608*bb02e0acSNicolas Bonnefon humanSize /= 1024.0; 609*bb02e0acSNicolas Bonnefon 610*bb02e0acSNicolas Bonnefon if ( humanSize >= 1024.0 ) { 611*bb02e0acSNicolas Bonnefon humanSize /= 1024.0; 612*bb02e0acSNicolas Bonnefon i++; 613*bb02e0acSNicolas Bonnefon } 614*bb02e0acSNicolas Bonnefon 615*bb02e0acSNicolas Bonnefon QString output; 616*bb02e0acSNicolas Bonnefon if ( i == 0 ) 617*bb02e0acSNicolas Bonnefon // No decimal part if we display straight bytes. 618*bb02e0acSNicolas Bonnefon output = defaultLocale.toString( (int) humanSize ); 619*bb02e0acSNicolas Bonnefon else 620*bb02e0acSNicolas Bonnefon output = defaultLocale.toString( humanSize, 'f', 1 ); 621*bb02e0acSNicolas Bonnefon 622*bb02e0acSNicolas Bonnefon output += QString(" ") + sizeStrs[i]; 623*bb02e0acSNicolas Bonnefon 624*bb02e0acSNicolas Bonnefon return output; 625*bb02e0acSNicolas Bonnefon } 626