VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/ui/VBoxVMLogViewer.ui.h@ 3797

Last change on this file since 3797 was 3797, checked in by vboxsync, 18 years ago

FE/Qt: VBoxVMLogViewer spelling.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 21.0 KB
Line 
1/**
2 *
3 * VBox frontends: Qt GUI ("VirtualBox"):
4 * "Virtual Log Viewer" dialog UI include (Qt Designer)
5 */
6
7/*
8 * Copyright (C) 2006 innotek GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.215389.xyz. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23/****************************************************************************
24** ui.h extension file, included from the uic-generated form implementation.
25**
26** If you wish to add, delete or rename functions or slots use
27** Qt Designer which will update this file, preserving your code. Create an
28** init() function in place of a constructor, and a destroy() function in
29** place of a destructor.
30*****************************************************************************/
31
32
33class VBoxLogSearchPanel : public QWidget
34{
35 Q_OBJECT
36
37public:
38
39 VBoxLogSearchPanel (QWidget *aParent,
40 VBoxVMLogViewer *aViewer,
41 const char *aName)
42 : QWidget (aParent, aName)
43 , mViewer (aViewer)
44 , mButtonClose (0)
45 , mSearchName (0), mSearchString (0)
46 , mButtonPrev (0), mButtonNext (0)
47 , mCaseSensitive (0)
48 , mWarningSpacer (0), mWarningIcon (0), mWarningString (0)
49 {
50 mButtonClose = new QToolButton (this);
51 mButtonClose->setAutoRaise (true);
52 mButtonClose->setFocusPolicy (QWidget::TabFocus);
53 mButtonClose->setAccel (QKeySequence (Qt::Key_Escape));
54 connect (mButtonClose, SIGNAL (clicked()), this, SLOT (hide()));
55 mButtonClose->setIconSet (VBoxGlobal::iconSet ("delete_16px.png",
56 "delete_dis_16px.png"));
57
58 mSearchName = new QLabel (this);
59 mSearchString = new QLineEdit (this);
60 mSearchString->setSizePolicy (QSizePolicy::Preferred,
61 QSizePolicy::Fixed);
62 connect (mSearchString, SIGNAL (textChanged (const QString &)),
63 this, SLOT (findCurrent (const QString &)));
64
65 mButtonPrev = new QToolButton (this);
66 mButtonPrev->setEnabled (false);
67 mButtonPrev->setAutoRaise (true);
68 mButtonPrev->setFocusPolicy (QWidget::TabFocus);
69 mButtonPrev->setUsesTextLabel (true);
70 mButtonPrev->setTextPosition (QToolButton::BesideIcon);
71 connect (mButtonPrev, SIGNAL (clicked()), this, SLOT (findBack()));
72 mButtonPrev->setIconSet (VBoxGlobal::iconSet ("list_moveup_16px.png",
73 "list_moveup_disabled_16px.png"));
74
75 mButtonNext = new QToolButton (this);
76 mButtonNext->setEnabled (false);
77 mButtonNext->setAutoRaise (true);
78 mButtonNext->setFocusPolicy (QWidget::TabFocus);
79 mButtonNext->setUsesTextLabel (true);
80 mButtonNext->setTextPosition (QToolButton::BesideIcon);
81 connect (mButtonNext, SIGNAL (clicked()), this, SLOT (findNext()));
82 mButtonNext->setIconSet (VBoxGlobal::iconSet ("list_movedown_16px.png",
83 "list_movedown_disabled_16px.png"));
84
85 mCaseSensitive = new QCheckBox (this);
86
87 mWarningSpacer = new QSpacerItem (0, 0, QSizePolicy::Fixed,
88 QSizePolicy::Minimum);
89 mWarningIcon = new QLabel (this);
90 mWarningIcon->hide();
91 QImage img = QMessageBox::standardIcon (QMessageBox::Warning).
92 convertToImage();
93 if (!img.isNull())
94 {
95 img = img.smoothScale (16, 16);
96 QPixmap pixmap;
97 pixmap.convertFromImage (img);
98 mWarningIcon->setPixmap (pixmap);
99 }
100 mWarningString = new QLabel (this);
101 mWarningString->hide();
102
103 QSpacerItem *spacer = new QSpacerItem (0, 0, QSizePolicy::Expanding,
104 QSizePolicy::Minimum);
105
106 QHBoxLayout *mainLayout = new QHBoxLayout (this, 5, 5);
107 mainLayout->addWidget (mButtonClose);
108 mainLayout->addWidget (mSearchName);
109 mainLayout->addWidget (mSearchString);
110 mainLayout->addWidget (mButtonNext);
111 mainLayout->addWidget (mButtonPrev);
112 mainLayout->addWidget (mCaseSensitive);
113 mainLayout->addItem (mWarningSpacer);
114 mainLayout->addWidget (mWarningIcon);
115 mainLayout->addWidget (mWarningString);
116 mainLayout->addItem (spacer);
117
118 setFocusProxy (mCaseSensitive);
119
120 languageChange();
121 }
122
123 void languageChange()
124 {
125 QToolTip::add (mButtonClose, tr ("Close the search panel"));
126 mSearchName->setText (tr ("Find "));
127 QToolTip::add (mSearchString, tr ("Enter a search string here"));
128 mButtonPrev->setTextLabel (tr ("&Previous"));
129 mButtonPrev->setAccel (QKeySequence (tr ("Alt+P")));
130 QToolTip::add (mButtonPrev,
131 tr ("Search for the previous occurrence of the string"));
132 mButtonNext->setTextLabel (tr ("&Next"));
133 mButtonNext->setAccel (QKeySequence (tr ("Alt+N")));
134 QToolTip::add (mButtonNext,
135 tr ("Search for the next occurrence of the string"));
136 mCaseSensitive->setText (tr ("C&ase Sensitive"));
137 QToolTip::add (mCaseSensitive,
138 tr ("Perform case sensitive search (when checked)"));
139 mWarningString->setText (tr ("String not found"));
140 }
141
142private slots:
143
144 void findNext()
145 {
146 search (true);
147 }
148
149 void findBack()
150 {
151 search (false);
152 }
153
154 void findCurrent (const QString &aSearchString)
155 {
156 mButtonNext->setEnabled (aSearchString.length());
157 mButtonPrev->setEnabled (aSearchString.length());
158 toggleWarning (!aSearchString.length());
159 if (aSearchString.length())
160 search (true, true);
161 else
162 mViewer->currentLogPage()->removeSelection();
163 }
164
165private:
166
167 void search (bool aForward, bool aStartCurrent = false)
168 {
169 QTextBrowser *browser = mViewer->currentLogPage();
170 int startPrg = 0, endPrg = 0;
171 int startInd = 0, endInd = 0;
172 if (browser->hasSelectedText())
173 browser->getSelection (&startPrg, &startInd, &endPrg, &endInd);
174
175 bool found = false;
176 int increment = aForward ? 1 : -1;
177 int border = aForward ? browser->paragraphs() : -1;
178 int startFrom = aStartCurrent ? startInd : startInd + increment;
179 int paragraph = startFrom < 0 ? startPrg + increment : startPrg;
180 for (; paragraph != border; paragraph += increment)
181 {
182 QString text = browser->text (paragraph);
183 int res = aForward ?
184 text.find (mSearchString->text(), startFrom,
185 mCaseSensitive->isChecked()) :
186 text.findRev (mSearchString->text(), startFrom,
187 mCaseSensitive->isChecked());
188 if (res != -1)
189 {
190 found = true;
191 browser->setSelection (paragraph, res, paragraph,
192 res + mSearchString->text().length());
193 break;
194 }
195 startFrom = aForward ? 0 : -1;
196 }
197
198 toggleWarning (found);
199 if (!found)
200 browser->setSelection (startPrg, startInd, endPrg, endInd);
201 }
202
203 bool eventFilter (QObject *aObject, QEvent *aEvent)
204 {
205 switch (aEvent->type())
206 {
207 case QEvent::KeyPress:
208 {
209 QKeyEvent *e = static_cast<QKeyEvent*> (aEvent);
210
211 /* processing the return keypress for the mSearchString
212 * widget as the search next string action */
213 if (aObject == mSearchString &&
214 (e->state() == 0 || e->state() & Keypad) &&
215 (e->key() == Key_Enter || e->key() == Key_Return))
216 {
217 findNext();
218 return true;
219 }
220 /* processing other search next/previous shortcuts */
221 else if (e->key() == Key_F3)
222 {
223 if (e->state() == 0)
224 findNext();
225 else if (e->state() == ShiftButton)
226 findBack();
227 return true;
228 }
229 /* processing ctrl-f key combination as the shortcut to
230 * move to the search field */
231 else if (e->state() == ControlButton && e->key() == Key_F)
232 {
233 mSearchString->setFocus();
234 return true;
235 }
236
237 break;
238 }
239 default:
240 break;
241 }
242 return false;
243 }
244
245 void showEvent (QShowEvent *aEvent)
246 {
247 QWidget::showEvent (aEvent);
248 qApp->installEventFilter (this);
249 mSearchString->setFocus();
250 }
251
252 void hideEvent (QHideEvent *aEvent)
253 {
254 if (focusData()->focusWidget()->parent() == this)
255 focusNextPrevChild (true);
256 qApp->removeEventFilter (this);
257 QWidget::hideEvent (aEvent);
258 }
259
260 void toggleWarning (bool aHide)
261 {
262 mWarningSpacer->changeSize (aHide ? 0 : 16, 0, QSizePolicy::Fixed,
263 QSizePolicy::Minimum);
264 mWarningIcon->setHidden (aHide);
265 mWarningString->setHidden (aHide);
266 }
267
268 VBoxVMLogViewer *mViewer;
269 QToolButton *mButtonClose;
270 QLabel *mSearchName;
271 QLineEdit *mSearchString;
272 QToolButton *mButtonPrev;
273 QToolButton *mButtonNext;
274 QCheckBox *mCaseSensitive;
275 QSpacerItem *mWarningSpacer;
276 QLabel *mWarningIcon;
277 QLabel *mWarningString;
278};
279
280
281VBoxVMLogViewer::LogViewersMap VBoxVMLogViewer::mSelfArray = LogViewersMap();
282
283void VBoxVMLogViewer::createLogViewer (CMachine &aMachine)
284{
285 if (mSelfArray.find (aMachine.GetName()) == mSelfArray.end())
286 {
287 /* creating new log viewer if there is no one existing */
288 mSelfArray [aMachine.GetName()] = new VBoxVMLogViewer (0,
289 "VBoxVMLogViewer", WType_TopLevel | WDestructiveClose);
290 /* read new machine data for this log viewer */
291 mSelfArray [aMachine.GetName()]->setup (aMachine);
292 }
293
294 VBoxVMLogViewer *viewer = mSelfArray [aMachine.GetName()];
295 viewer->show();
296 viewer->setWindowState (viewer->windowState() & ~WindowMinimized);
297 viewer->setActiveWindow();
298}
299
300
301void VBoxVMLogViewer::init()
302{
303 /* prepare dialog to first run */
304 mFirstRun = true;
305
306 /* dialog initially is not polished */
307 mIsPolished = false;
308
309 /* search the default button */
310 mDefaultButton = searchDefaultButton();
311 qApp->installEventFilter (this);
312
313 /* setup a dialog icon */
314 setIcon (QPixmap::fromMimeSource ("show_logs_16px.png"));
315
316 /* statusbar initially disabled */
317 statusBar()->setHidden (true);
318
319 /* setup size grip */
320 mSizeGrip = new QSizeGrip (centralWidget(), "mSizeGrip");
321 mSizeGrip->resize (mSizeGrip->sizeHint());
322 mSizeGrip->stackUnder (mCloseButton);
323
324 /* logs list creation */
325 mLogList = new QTabWidget (mLogsFrame, "mLogList");
326 QVBoxLayout *logsFrameLayout = new QVBoxLayout (mLogsFrame);
327 logsFrameLayout->addWidget (mLogList);
328
329 /* search panel creation */
330 mSearchPanel = new VBoxLogSearchPanel (mLogsFrame, this,
331 "VBoxLogSearchPanel");
332 logsFrameLayout->addWidget (mSearchPanel);
333 mSearchPanel->hide();
334
335 /* fix the tab order to ensure the dialog keys are always the last */
336 setTabOrder (mSearchPanel->focusProxy(), mSaveButton);
337 setTabOrder (mSaveButton, mRefreshButton);
338 setTabOrder (mRefreshButton, mCloseButton);
339 setTabOrder (mCloseButton, mLogList);
340
341 /* applying language settings */
342 languageChangeImp();
343}
344
345
346void VBoxVMLogViewer::destroy()
347{
348 mSelfArray.erase (mMachine.GetName());
349}
350
351
352void VBoxVMLogViewer::setup (CMachine &aMachine)
353{
354 /* saving related machine */
355 mMachine = aMachine;
356
357 /* reading log files */
358 refresh();
359
360 /* loading language constants */
361 languageChangeImp();
362}
363
364
365const CMachine& VBoxVMLogViewer::machine()
366{
367 return mMachine;
368}
369
370
371void VBoxVMLogViewer::languageChangeImp()
372{
373 /* setup a dialog caption */
374 if (!mMachine.isNull())
375 setCaption (tr ("%1 - VirtualBox Log Viewer").arg (mMachine.GetName()));
376 /* translate a search panel */
377 if (mSearchPanel)
378 mSearchPanel->languageChange();
379}
380
381
382QPushButton* VBoxVMLogViewer::searchDefaultButton()
383{
384 /* this mechanism is used for searching the default dialog button
385 * and similar the same mechanism in Qt::QDialog inner source */
386 QPushButton *button = 0;
387 QObjectList *list = queryList ("QPushButton");
388 QObjectListIt it (*list);
389 while ((button = (QPushButton*)it.current()) && !button->isDefault())
390 ++ it;
391 return button;
392}
393
394
395bool VBoxVMLogViewer::eventFilter (QObject *aObject, QEvent *aEvent)
396{
397 switch (aEvent->type())
398 {
399 /* auto-default button focus-in processor used to move the "default"
400 * button property into the currently focused button */
401 case QEvent::FocusIn:
402 {
403 if (aObject->inherits ("QPushButton") &&
404 aObject->parent() == centralWidget())
405 {
406 ((QPushButton*)aObject)->setDefault (aObject != mDefaultButton);
407 if (mDefaultButton)
408 mDefaultButton->setDefault (aObject == mDefaultButton);
409 }
410 break;
411 }
412 /* auto-default button focus-out processor used to remove the "default"
413 * button property from the previously focused button */
414 case QEvent::FocusOut:
415 {
416 if (aObject->inherits ("QPushButton") &&
417 aObject->parent() == centralWidget())
418 {
419 if (mDefaultButton)
420 mDefaultButton->setDefault (aObject != mDefaultButton);
421 ((QPushButton*)aObject)->setDefault (aObject == mDefaultButton);
422 }
423 break;
424 }
425 default:
426 break;
427 }
428 return QMainWindow::eventFilter (aObject, aEvent);
429}
430
431
432bool VBoxVMLogViewer::event (QEvent *aEvent)
433{
434 bool result = QMainWindow::event (aEvent);
435 switch (aEvent->type())
436 {
437 case QEvent::LanguageChange:
438 {
439 languageChangeImp();
440 break;
441 }
442 default:
443 break;
444 }
445 return result;
446}
447
448
449void VBoxVMLogViewer::keyPressEvent (QKeyEvent *aEvent)
450{
451 if (aEvent->state() == 0 ||
452 (aEvent->state() & Keypad && aEvent->key() == Key_Enter))
453 {
454 switch (aEvent->key())
455 {
456 /* processing the return keypress for the auto-default button */
457 case Key_Enter:
458 case Key_Return:
459 {
460 QPushButton *currentDefault = searchDefaultButton();
461 if (currentDefault)
462 currentDefault->animateClick();
463 break;
464 }
465 /* processing the escape keypress as the close dialog action */
466 case Key_Escape:
467 {
468 mCloseButton->animateClick();
469 break;
470 }
471 }
472 }
473 else if (aEvent->state() == Qt::ControlButton &&
474 aEvent->key() == Qt::Key_F)
475 {
476 if (mLogList->isEnabled())
477 mSearchPanel->show();
478 }
479 else
480 aEvent->ignore();
481}
482
483
484void VBoxVMLogViewer::showEvent (QShowEvent *aEvent)
485{
486 QMainWindow::showEvent (aEvent);
487
488 /* one may think that QWidget::polish() is the right place to do things
489 * below, but apparently, by the time when QWidget::polish() is called,
490 * the widget style & layout are not fully done, at least the minimum
491 * size hint is not properly calculated. Since this is sometimes necessary,
492 * we provide our own "polish" implementation. */
493
494 if (mIsPolished)
495 return;
496
497 mIsPolished = true;
498
499 VBoxGlobal::centerWidget (this, parentWidget());
500}
501
502
503void VBoxVMLogViewer::resizeEvent (QResizeEvent*)
504{
505 /* adjust the size-grip location for the current resize event */
506 mSizeGrip->move (centralWidget()->rect().bottomRight() -
507 QPoint (mSizeGrip->rect().width() - 1,
508 mSizeGrip->rect().height() - 1));
509}
510
511
512void VBoxVMLogViewer::refresh()
513{
514 /* clearing old data if any */
515 mLogFilesList.clear();
516 while (mLogList->count())
517 {
518 QWidget *logPage = mLogList->page (0);
519 mLogList->removePage (logPage);
520 delete logPage;
521 }
522
523 bool isAnyLogPresent = false;
524
525 /* entering log files folder */
526 QString logFilesPath = mMachine.GetLogFolder();
527 QDir logFilesDir (logFilesPath);
528 if (logFilesDir.exists())
529 {
530 /* reading log files folder */
531 QStringList logList = logFilesDir.entryList (QDir::Files);
532 if (!logList.empty()) isAnyLogPresent = true;
533 for (QStringList::Iterator it = logList.begin(); it != logList.end(); ++it)
534 loadLogFile (logFilesDir.filePath (*it));
535 }
536
537 /* create an empty log page if there are no logs at all */
538 if (!isAnyLogPresent)
539 {
540 QTextBrowser *dummyLog = createLogPage ("VBox.log");
541 dummyLog->setTextFormat (Qt::RichText);
542 dummyLog->setWordWrap (QTextEdit::WidgetWidth);
543 dummyLog->setText (tr ("<p>No log files found. Press the <b>Refresh</b> "
544 "button to rescan the log folder <nobr><b>%1</b></nobr>.</p>")
545 .arg (logFilesPath));
546 /* we don't want it to remain white */
547 dummyLog->setPaper (backgroundBrush());
548 }
549
550 /* restore previous tab-widget margin which was reseted when
551 * the tab widget's children was removed */
552 mLogList->setMargin (10);
553
554 /* show the first tab widget's page after the refresh */
555 mLogList->showPage (mLogList->page(0));
556
557 /* enable/disable save button & tab widget according log presence */
558 mSaveButton->setEnabled (isAnyLogPresent);
559 mLogList->setEnabled (isAnyLogPresent);
560
561 if (mFirstRun)
562 {
563 /* resize the whole log-viewer to fit 80 symbols in text-browser for
564 * the first time started */
565 QTextBrowser *firstPage = static_cast <QTextBrowser *> (mLogList->page(0));
566 int fullWidth = firstPage->fontMetrics().width (QChar ('x')) * 80 +
567 firstPage->verticalScrollBar()->width() +
568 firstPage->frameWidth() * 2 +
569 5 + 4 /* left text margin + QTabWidget frame width */ +
570 mLogList->margin() * 2 +
571 centralWidget()->layout()->margin() * 2;
572 resize (fullWidth, height());
573 mFirstRun = false;
574 }
575}
576
577
578void VBoxVMLogViewer::loadLogFile (const QString &aFileName)
579{
580 /* prepare log file */
581 QFile logFile (aFileName);
582 if (!logFile.exists() || !logFile.open (IO_ReadOnly))
583 return;
584
585 /* read log file and write it into the log page */
586 QTextBrowser *logViewer = createLogPage (QFileInfo (aFileName).fileName());
587 logViewer->setText (logFile.readAll());
588
589 mLogFilesList << aFileName;
590}
591
592
593QTextBrowser* VBoxVMLogViewer::createLogPage (const QString &aName)
594{
595 QTextBrowser *logViewer = new QTextBrowser();
596 logViewer->setTextFormat (Qt::PlainText);
597 QFont font = logViewer->currentFont();
598 font.setFamily ("Courier New,courier");
599 logViewer->setFont (font);
600 logViewer->setWordWrap (QTextEdit::NoWrap);
601 logViewer->setVScrollBarMode (QScrollView::AlwaysOn);
602 mLogList->addTab (logViewer, aName);
603 return logViewer;
604}
605
606
607QTextBrowser* VBoxVMLogViewer::currentLogPage()
608{
609 return static_cast<QTextBrowser*> (mLogList->currentPage());
610}
611
612
613void VBoxVMLogViewer::save()
614{
615 /* prepare "save as" dialog */
616 QFileInfo fileInfo (mLogFilesList [mLogList->currentPageIndex()]);
617 QDateTime dtInfo = fileInfo.lastModified();
618 QString dtString = dtInfo.toString ("yyyy-MM-dd-hh-mm-ss");
619 QString defaultFileName = QString ("%1-%2.log")
620 .arg (mMachine.GetName()).arg (dtString);
621 QString defaultFullName = QDir::convertSeparators (QDir::home().absPath() +
622 "/" + defaultFileName);
623
624 QString newFileName = QFileDialog::getSaveFileName (defaultFullName,
625 QString::null, this, "SaveLogAsDialog", tr ("Save VirtualBox Log As"));
626
627 /* save new log into the file */
628 if (!newFileName.isEmpty())
629 {
630 /* reread log data */
631 QFile oldFile (mLogFilesList [mLogList->currentPageIndex()]);
632 QFile newFile (newFileName);
633 if (!oldFile.open (IO_ReadOnly) || !newFile.open (IO_WriteOnly))
634 return;
635
636 /* save log data into the new file */
637 newFile.writeBlock (oldFile.readAll());
638 }
639}
640
641#include "VBoxVMLogViewer.ui.moc"
642
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette