wireshark/ui/qt/print_dialog.cpp

323 lines
9.6 KiB
C++

/* print_dialog.cpp
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "print_dialog.h"
#include "ui_print_dialog.h"
#include <QPrintDialog>
#include <QPageSetupDialog>
#include <QPainter>
#include <QPaintEngine>
#include <QKeyEvent>
#include <QMessageBox>
#include "wireshark_application.h"
extern "C" {
// Page element callbacks
static gboolean
print_preamble_pd(print_stream_t *self, gchar *filename)
{
Q_UNUSED(filename);
if (!self) return FALSE;
PrintDialog *print_dlg = static_cast<PrintDialog *>(self->data);
if (!print_dlg) return FALSE;
return print_dlg->printHeader();
}
static gboolean
print_line_pd(print_stream_t *self, int indent, const char *line)
{
if (!self) return FALSE;
PrintDialog *print_dlg = static_cast<PrintDialog *>(self->data);
if (!print_dlg) return FALSE;
return print_dlg->printLine(indent, line);
}
static gboolean
new_page_pd(print_stream_t *self)
{
if (!self) return FALSE;
PrintDialog *print_dlg = static_cast<PrintDialog *>(self->data);
if (!print_dlg) return FALSE;
return print_dlg->printHeader();
}
} // extern "C"
PrintDialog::PrintDialog(QWidget *parent, capture_file *cf) :
QDialog(parent),
pd_ui_(new Ui::PrintDialog),
cur_printer_(NULL),
cur_painter_(NULL),
preview_(new QPrintPreviewWidget(&printer_)),
print_bt_(new QPushButton(tr("&Print..."))),
cap_file_(cf)
{
if (!cf) done(QDialog::Rejected); // ...or assert?
pd_ui_->setupUi(this);
pd_ui_->previewLayout->insertWidget(0, preview_, Qt::AlignTop);
preview_->setMinimumWidth(preview_->height() / 2);
preview_->setToolTip(pd_ui_->zoomLabel->toolTip());
// XXX Make these configurable
header_font_.setFamily("Times");
header_font_.setPointSizeF(header_font_.pointSizeF() * 0.8);
packet_font_ = wsApp->monospaceFont();
packet_font_.setPointSizeF(packet_font_.pointSizeF() * 0.8);
memset(&print_args_, 0, sizeof(print_args_));
memset(&stream_ops_, 0, sizeof(stream_ops_));
/* Init the export range */
packet_range_init(&print_args_.range, cap_file_);
/* Default to displayed packets */
print_args_.range.process_filtered = TRUE;
stream_ops_.print_preamble = print_preamble_pd;
stream_ops_.print_line = print_line_pd;
stream_ops_.new_page = new_page_pd;
stream_.data = this;
stream_.ops = &stream_ops_;
print_args_.stream = &stream_;
gchar *display_basename = g_filename_display_basename(cap_file_->filename);
printer_.setDocName(display_basename);
g_free(display_basename);
pd_ui_->rangeGroupBox->initRange(&print_args_.range);
pd_ui_->buttonBox->addButton(print_bt_, QDialogButtonBox::ActionRole);
pd_ui_->buttonBox->addButton(tr("Page &Setup..."), QDialogButtonBox::ResetRole);
print_bt_->setDefault(true);
connect(preview_, SIGNAL(paintRequested(QPrinter*)), this, SLOT(paintPreview(QPrinter*)));
connect(pd_ui_->rangeGroupBox, SIGNAL(rangeChanged()),
this, SLOT(checkValidity()));
connect(pd_ui_->formatGroupBox, SIGNAL(formatChanged()),
this, SLOT(checkValidity()));
connect(pd_ui_->formFeedCheckBox, SIGNAL(toggled(bool)),
preview_, SLOT(updatePreview()));
checkValidity();
}
PrintDialog::~PrintDialog()
{
delete pd_ui_;
}
// Public
gboolean PrintDialog::printHeader()
{
if (!cap_file_ || !cap_file_->filename || !cur_printer_ || !cur_painter_) return FALSE;
int page_top = cur_printer_->pageRect().top();
if (page_pos_ > page_top) {
if (in_preview_) {
return FALSE;
}
// Second and subsequent pages only
cur_printer_->newPage();
page_pos_ = page_top;
}
QString banner = QString("%1 %2 total packets, %3 shown")
.arg(cap_file_->filename)
.arg(cap_file_->count)
.arg(cap_file_->displayed_count);
cur_painter_->setFont(header_font_);
cur_painter_->drawText(0, page_top, banner);
page_pos_ += cur_painter_->fontMetrics().height();
cur_painter_->setFont(packet_font_);
return TRUE;
}
gboolean PrintDialog::printLine(int indent, const char *line)
{
QRect out_rect;
QString out_line;
if (!line || !cur_printer_ || !cur_painter_) return FALSE;
/* Prepare the tabs for printing, depending on tree level */
out_line.fill(' ', indent * 4);
out_line += line;
out_rect = cur_painter_->boundingRect(cur_printer_->pageRect(), Qt::TextWordWrap, out_line);
if (cur_printer_->pageRect().height() < page_pos_ + out_rect.height()) {
if (in_preview_) {
return FALSE;
}
if (*line == '\0') { // Separator
return TRUE;
}
printHeader();
}
out_rect.translate(0, page_pos_);
cur_painter_->drawText(out_rect, Qt::TextWordWrap, out_line);
page_pos_ += out_rect.height();
return TRUE;
}
// Protected
void PrintDialog::keyPressEvent(QKeyEvent *event)
{
// XXX - This differs from the main window but matches other applications (e.g. Mozilla and Safari)
switch(event->key()) {
case Qt::Key_Minus:
case Qt::Key_Underscore: // Shifted minus on U.S. keyboards
preview_->zoomOut();
break;
case Qt::Key_Plus:
case Qt::Key_Equal: // Unshifted plus on U.S. keyboards
preview_->zoomIn();
break;
case Qt::Key_0:
case Qt::Key_ParenRight: // Shifted 0 on U.S. keyboards
// fitInView doesn't grow (at least in Qt 4.8.2) so make sure it shrinks.
preview_->setUpdatesEnabled(false);
preview_->setZoomFactor(1.0);
preview_->fitInView();
preview_->setUpdatesEnabled(true);
break;
}
QDialog::keyPressEvent(event);
}
// Private
void PrintDialog::printPackets(QPrinter *printer, bool in_preview)
{
QPainter painter;
cf_print_status_t status;
if (!printer) return;
page_pos_ = printer->pageRect().top();
in_preview_ = in_preview;
/* Fill in our print args */
print_args_.format = PR_FMT_TEXT;
print_args_.print_summary = pd_ui_->formatGroupBox->summaryEnabled();
print_args_.print_hex = pd_ui_->formatGroupBox->bytesEnabled();
print_args_.print_formfeed = pd_ui_->formFeedCheckBox->isChecked();
print_args_.print_dissections = print_dissections_none;
if (pd_ui_->formatGroupBox->detailsEnabled()) {
if (pd_ui_->formatGroupBox->allCollapsedEnabled())
print_args_.print_dissections = print_dissections_collapsed;
else if (pd_ui_->formatGroupBox->asDisplayedEnabled())
print_args_.print_dissections = print_dissections_as_displayed;
else if (pd_ui_->formatGroupBox->allExpandedEnabled())
print_args_.print_dissections = print_dissections_expanded;
}
// This should be identical to printer_. However, the QPrintPreviewWidget docs
// tell us to draw on the printer handed to us by the paintRequested() signal.
cur_printer_ = printer;
cur_painter_ = &painter;
if (!painter.begin(printer)) {
QMessageBox::warning(this, tr("Print Error"),
QString(tr("Unable to print to %1.")).arg(printer_.printerName()),
QMessageBox::Ok);
close();
}
// cf_print_packets updates the progress bar which in turn calls
// WiresharkApplication::processEvents(), which can make the preview trip
// over itself.
preview_->setUpdatesEnabled(false);
status = cf_print_packets(cap_file_, &print_args_);
preview_->setUpdatesEnabled(true);
cur_printer_ = NULL;
cur_painter_ = NULL;
painter.end();
}
void PrintDialog::paintPreview(QPrinter *printer)
{
printPackets(printer, true);
}
void PrintDialog::checkValidity()
{
bool enable = true;
if (!pd_ui_->rangeGroupBox->isValid()) enable = false;
if ( ! pd_ui_->formatGroupBox->summaryEnabled() &&
! pd_ui_->formatGroupBox->detailsEnabled() &&
! pd_ui_->formatGroupBox->bytesEnabled() ) {
enable = false;
}
print_bt_->setEnabled(enable);
preview_->updatePreview();
}
void PrintDialog::on_buttonBox_helpRequested()
{
wsApp->helpTopicAction(HELP_PRINT_DIALOG);
}
void PrintDialog::on_buttonBox_clicked(QAbstractButton *button)
{
QPrintDialog *print_dlg;
QPageSetupDialog *ps_dlg;
switch (pd_ui_->buttonBox->buttonRole(button)) {
case QDialogButtonBox::ActionRole:
int result;
print_dlg = new QPrintDialog(&printer_, this);
result = print_dlg->exec();
if (result == QDialog::Accepted) {
printPackets(&printer_, false);
done(result);
}
break;
case QDialogButtonBox::ResetRole:
ps_dlg = new QPageSetupDialog(&printer_, this);
ps_dlg->exec();
preview_->updatePreview();
break;
default: // Help, Cancel
break;
}
}