VirtualBox

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

Last change on this file since 13835 was 8155, checked in by vboxsync, 17 years ago

The Big Sun Rebranding Header Change

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

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