frame_data *PacketListModel::getRowFdata(int row) {
    if (row < 0 || row >= visible_rows_.count())
        return NULL;
    PacketListRecord *record = visible_rows_[row];
    if (!record)
        return NULL;
    return record->frameData();
}
void PacketListModel::resetColorized()
{
    PacketListRecord *record;

    beginResetModel();
    foreach (record, physical_rows_) {
        record->resetColorized();
    }
    endResetModel();
}
guint PacketListModel::recreateVisibleRows()
{
    int pos = visible_rows_.count() + 1;
    PacketListRecord *record;

    beginResetModel();
    visible_rows_.clear();
    endResetModel();
    beginInsertRows(QModelIndex(), pos, pos);
    foreach (record, physical_rows_) {
        if (record->getFdata()->flags.passed_dfilter || record->getFdata()->flags.ref_time) {
            visible_rows_ << record;
        }
    }
    endInsertRows();
    return visible_rows_.count();
}
guint PacketListModel::recreateVisibleRows()
{
    int pos = visible_rows_.count();
    PacketListRecord *record;

    beginResetModel();
    visible_rows_.clear();
    number_to_row_.clear();
    if (cap_file_) {
        PacketListRecord::resetColumns(&cap_file_->cinfo);
    }
    endResetModel();
    beginInsertRows(QModelIndex(), pos, pos);
    foreach (record, physical_rows_) {
        if (record->frameData()->flags.passed_dfilter || record->frameData()->flags.ref_time) {
            visible_rows_ << record;
            number_to_row_[record->frameData()->num] = visible_rows_.count() - 1;
        }
    }
    endInsertRows();
    return visible_rows_.count();
}
QVariant PacketListModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    PacketListRecord *record = static_cast<PacketListRecord*>(index.internalPointer());
    if (!record)
        return QVariant();
    const frame_data *fdata = record->frameData();
    if (!fdata)
        return QVariant();

    switch (role) {
    case Qt::FontRole:
        return mono_font_;
    case Qt::TextAlignmentRole:
        switch(recent_get_column_xalign(index.column())) {
        case COLUMN_XALIGN_RIGHT:
            return Qt::AlignRight;
            break;
        case COLUMN_XALIGN_CENTER:
            return Qt::AlignCenter;
            break;
        case COLUMN_XALIGN_LEFT:
            return Qt::AlignLeft;
            break;
        case COLUMN_XALIGN_DEFAULT:
        default:
            if (right_justify_column(index.column(), cap_file_)) {
                return Qt::AlignRight;
            }
            break;
        }
        return Qt::AlignLeft;

    case Qt::BackgroundRole:
        const color_t *color;
        if (fdata->flags.ignored) {
            color = &prefs.gui_ignored_bg;
        } else if (fdata->flags.marked) {
            color = &prefs.gui_marked_bg;
        } else if (fdata->color_filter && recent.packet_list_colorize) {
            const color_filter_t *color_filter = (const color_filter_t *) fdata->color_filter;
            color = &color_filter->bg_color;
        } else {
            return QVariant();
        }
        return QColor(color->red >> 8, color->green >> 8, color->blue >> 8);
    case Qt::ForegroundRole:
        if (fdata->flags.ignored) {
            color = &prefs.gui_ignored_fg;
        } else if (fdata->flags.marked) {
            color = &prefs.gui_marked_fg;
        } else if (fdata->color_filter && recent.packet_list_colorize) {
            const color_filter_t *color_filter = (const color_filter_t *) fdata->color_filter;
            color = &color_filter->fg_color;
        } else {
            return QVariant();
        }
        return QColor(color->red >> 8, color->green >> 8, color->blue >> 8);
    case Qt::DisplayRole:
    {
        int column = index.column();
        QVariant column_string = record->columnString(cap_file_, column);
        // We don't know an item's sizeHint until we fetch its text here.
        // Assume each line count is 1. If the line count changes, emit
        // itemHeightChanged which triggers another redraw (including a
        // fetch of SizeHintRole and DisplayRole) in the next event loop.
        if (column == 0 && record->lineCountChanged())
            emit itemHeightChanged(index);
        return column_string;
    }
    case Qt::SizeHintRole:
    {
        if (size_hint_enabled_) {
            // We assume that inter-line spacing is 0.
            QSize size = QSize(-1, row_height_ + ((record->lineCount() - 1) * line_spacing_));
            return size;
        } else {
            // Used by PacketList::sizeHintForColumn
            return QVariant();
        }
    }
    default:
        return QVariant();
    }

    return QVariant();
}
QVariant PacketListModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    PacketListRecord *record = static_cast<PacketListRecord*>(index.internalPointer());
    if (!record)
        return QVariant();
    frame_data *fdata = record->frameData();
    if (!fdata)
        return QVariant();

    switch (role) {
    case Qt::FontRole:
        return wsApp->monospaceFont();
    case Qt::TextAlignmentRole:
        switch(recent_get_column_xalign(index.column())) {
        case COLUMN_XALIGN_RIGHT:
            return Qt::AlignRight;
            break;
        case COLUMN_XALIGN_CENTER:
            return Qt::AlignCenter;
            break;
        case COLUMN_XALIGN_LEFT:
            return Qt::AlignLeft;
            break;
        case COLUMN_XALIGN_DEFAULT:
        default:
            if (right_justify_column(index.column(), cap_file_)) {
                return Qt::AlignRight;
            }
            break;
        }
        return Qt::AlignLeft;

    case Qt::BackgroundRole:
        const color_t *color;
        if (fdata->flags.ignored) {
            color = &prefs.gui_ignored_bg;
        } else if (fdata->flags.marked) {
            color = &prefs.gui_marked_bg;
        } else if (fdata->color_filter) {
            const color_filter_t *color_filter = (const color_filter_t *) fdata->color_filter;
            color = &color_filter->bg_color;
        } else {
            return QVariant();
        }
//        g_log(NULL, G_LOG_LEVEL_DEBUG, "i: %d m: %d cf: %p bg: %d %d %d", fdata->flags.ignored, fdata->flags.marked, fdata->color_filter, color->red, color->green, color->blue);
        return QColor(color->red >> 8, color->green >> 8, color->blue >> 8);
    case Qt::ForegroundRole:
        if (fdata->flags.ignored) {
            color = &prefs.gui_ignored_fg;
        } else if (fdata->flags.marked) {
            color = &prefs.gui_marked_fg;
        } else if (fdata->color_filter) {
            const color_filter_t *color_filter = (const color_filter_t *) fdata->color_filter;
            color = &color_filter->fg_color;
        } else {
            return QVariant();
        }
        return QColor(color->red >> 8, color->green >> 8, color->blue >> 8);
    case Qt::DisplayRole:
    {
        int column = index.column();
        //    g_log(NULL, G_LOG_LEVEL_DEBUG, "showing col %d", col_num);
        return record->columnString(cap_file_, column);
    }
    default:
        return QVariant();
    }

    return QVariant();
}
void RelatedPacketDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
                              const QModelIndex &index) const
{
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
    QStyleOptionViewItemV4 option_vi = option;
#else
    QStyleOptionViewItem option_vi = option;
#endif
    QStyledItemDelegate::initStyleOption(&option_vi, index);
    int em_w = option_vi.fontMetrics.height();
    int en_w = (em_w + 1) / 2;
    int line_w = (option_vi.fontMetrics.lineWidth());

#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
    option_vi.features |= QStyleOptionViewItemV4::HasDecoration;
#else
    option_vi.features |= QStyleOptionViewItem::HasDecoration;
#endif
    option_vi.decorationSize.setHeight(1);
    option_vi.decorationSize.setWidth(em_w);
    QStyledItemDelegate::paint(painter, option_vi, index);

    guint32 setup_frame = 0, last_frame = 0;
    if (conv_) {
        setup_frame = (int) conv_->setup_frame;
        last_frame = (int) conv_->last_frame;
    }

    const frame_data *fd;
    PacketListRecord *record = static_cast<PacketListRecord*>(index.internalPointer());
    if (!record || (fd = record->frameData()) == NULL) {
        return;
    }

    painter->save();

    if (QApplication::style()->objectName().contains("vista")) {
        // QWindowsVistaStyle::drawControl does this internally. Unfortunately there
        // doesn't appear to be a more general way to do this.
        option_vi.palette.setColor(QPalette::All, QPalette::HighlightedText, option_vi.palette.color(QPalette::Active, QPalette::Text));
    }

    QPalette::ColorGroup cg = option_vi.state & QStyle::State_Enabled
                              ? QPalette::Normal : QPalette::Disabled;
    QColor fg;
    if (cg == QPalette::Normal && !(option_vi.state & QStyle::State_Active))
        cg = QPalette::Inactive;
    if (option_vi.state & QStyle::State_Selected) {
        fg = option_vi.palette.color(cg, QPalette::HighlightedText);
    } else {
        fg = option_vi.palette.color(cg, QPalette::Text);
    }

    fg = ColorUtils::alphaBlend(fg, option_vi.palette.color(cg, QPalette::Base), 0.5);
    QPen line_pen(fg);
    line_pen.setWidth(line_w);
    line_pen.setJoinStyle(Qt::RoundJoin);

    painter->setPen(line_pen);
    painter->translate(option_vi.rect.x(), option_vi.rect.y());
    painter->translate(en_w + 0.5, 0.5);
    painter->setRenderHint(QPainter::Antialiasing, true);
    int height = option_vi.rect.height();

    // Uncomment to make the boundary visible.
//    painter->save();
//    painter->setPen(Qt::darkRed);
//    painter->drawRect(QRectF(0.5, 0.5, en_w - 1, height - 1));
//    painter->restore();

    // The current decorations are based on what looked good and were easy
    // to code.

    // It might be useful to have a JACKPOT_MODE define that shows each
    // decoration in sequence in order to make it easier to create
    // screenshots for the User's Guide.

    // Vertical line. Lower and upper half for the start and end of the
    // conversation respectively, solid for conversation member, dashed
    // for other packets in the start-end range.
    if (setup_frame > 0 && last_frame > 0 && setup_frame != last_frame) {
        if (fd->num == setup_frame) {
            QPoint start_line[] = {
                QPoint(en_w - 1, height / 2),
                QPoint(0, height / 2),
                QPoint(0, height)
            };
            painter->drawPolyline(start_line, 3);
        } else if (fd->num > setup_frame && fd->num < last_frame) {
            painter->save();
            if (conv_ != record->conversation()) {
                QPen other_pen(line_pen);
                other_pen.setStyle(Qt::DashLine);
                painter->setPen(other_pen);
            }
            painter->drawLine(0, 0, 0, height);
            painter->restore();
        } else if (fd->num == last_frame) {
            QPoint end_line[] = {
                QPoint(en_w - 1, height / 2),
                QPoint(0, height / 2),
                QPoint(0, 0)
            };
            painter->drawPolyline(end_line, 3);
        }
    }

    // Related packet indicator. Rightward arrow for requests, leftward
    // arrow for responses, circle for others.
    // XXX These are comically oversized when we have multi-line rows.
    if (related_frames_.contains(fd->num)) {
        painter->setBrush(fg);
        switch (related_frames_[fd->num]) {
        // Request and response arrows are moved forward one pixel in order to
        // maximize white space between the heads and the conversation line.
        case FT_FRAMENUM_REQUEST:
        {
            int hh = height / 2;
            QPoint tail(2 - en_w, hh);
            QPoint head(en_w, hh);
            drawArrow(painter, tail, head, hh / 2);
            break;
        }
        case FT_FRAMENUM_RESPONSE:
        {
            int hh = height / 2;
            QPoint tail(en_w - 1, hh);
            QPoint head(1 - en_w, hh);
            drawArrow(painter, tail, head, hh / 2);
            break;
        }
        case FT_FRAMENUM_ACK:
        {
            QRect bbox (2 - en_w, height / 3, em_w - 2, height / 2);
            drawCheckMark(painter, bbox);
            break;
        }
        case FT_FRAMENUM_DUP_ACK:
        {
            QRect bbox (2 - en_w, (height / 3) - (line_w * 2), em_w - 2, height / 2);
            drawCheckMark(painter, bbox);
            bbox.moveTop(bbox.top() + (line_w * 3));
            drawCheckMark(painter, bbox);
            break;
        }
        case FT_FRAMENUM_NONE:
        default:
            painter->drawEllipse(QPointF(0.0, option_vi.rect.height() / 2), 2, 2);
        }
    }

    painter->restore();
}
QVariant PacketListModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    PacketListRecord *record = static_cast<PacketListRecord*>(index.internalPointer());
    if (!record)
        return QVariant();
    frame_data *fdata = record->getFdata();
    if (!fdata)
        return QVariant();

    switch (role) {
    case Qt::FontRole:
        return wsApp->monospaceFont();
    case Qt::TextAlignmentRole:
        switch(recent_get_column_xalign(index.column())) {
        case COLUMN_XALIGN_RIGHT:
            return Qt::AlignRight;
            break;
        case COLUMN_XALIGN_CENTER:
            return Qt::AlignCenter;
            break;
        case COLUMN_XALIGN_LEFT:
            return Qt::AlignLeft;
            break;
        case COLUMN_XALIGN_DEFAULT:
        default:
            if (right_justify_column(index.column(), cap_file_)) {
                return Qt::AlignRight;
            }
            break;
        }
        return Qt::AlignLeft;

    case Qt::BackgroundRole:
        const color_t *color;
        if (fdata->flags.ignored) {
            color = &prefs.gui_ignored_bg;
        } else if (fdata->flags.marked) {
            color = &prefs.gui_marked_bg;
        } else if (fdata->color_filter) {
            const color_filter_t *color_filter = (const color_filter_t *) fdata->color_filter;
            color = &color_filter->bg_color;
        } else {
            return QVariant();
        }
//        g_log(NULL, G_LOG_LEVEL_DEBUG, "i: %d m: %d cf: %p bg: %d %d %d", fdata->flags.ignored, fdata->flags.marked, fdata->color_filter, color->red, color->green, color->blue);
        return QColor(color->red >> 8, color->green >> 8, color->blue >> 8);
    case Qt::ForegroundRole:
        if (fdata->flags.ignored) {
            color = &prefs.gui_ignored_fg;
        } else if (fdata->flags.marked) {
            color = &prefs.gui_marked_fg;
        } else if (fdata->color_filter) {
            const color_filter_t *color_filter = (const color_filter_t *) fdata->color_filter;
            color = &color_filter->fg_color;
        } else {
            return QVariant();
        }
        return QColor(color->red >> 8, color->green >> 8, color->blue >> 8);
    case Qt::DisplayRole:
        // Need packet data -- fall through
        break;
    default:
        return QVariant();
    }

    int col_num = index.column();
//    g_log(NULL, G_LOG_LEVEL_DEBUG, "showing col %d", col_num);

    if (!cap_file_ || col_num > cap_file_->cinfo.num_cols)
        return QVariant();

    epan_dissect_t edt;
    column_info *cinfo;
    gboolean create_proto_tree;
    struct wtap_pkthdr phdr; /* Packet header */
    Buffer buf;  /* Packet data */
    gboolean dissect_columns = TRUE; // XXX - Currently only a placeholder

    if (dissect_columns && cap_file_)
        cinfo = &cap_file_->cinfo;
    else
        cinfo = NULL;

    buffer_init(&buf, 1500);
    if (!cap_file_ || !cf_read_frame_r(cap_file_, fdata, &phdr, &buf)) {
        /*
         * Error reading the frame.
         *
         * Don't set the color filter for now (we might want
         * to colorize it in some fashion to warn that the
         * row couldn't be filled in or colorized), and
         * set the columns to placeholder values, except
         * for the Info column, where we'll put in an
         * error message.
         */
        if (dissect_columns) {
            col_fill_in_error(cinfo, fdata, FALSE, FALSE /* fill_fd_columns */);

            //            for(gint col = 0; col < cinfo->num_cols; ++col) {
            //                /* Skip columns based on frame_data because we already store those. */
            //                if (!col_based_on_frame_data(cinfo, col))
            //                    packet_list_change_record(packet_list, record->physical_pos, col, cinfo);
            //            }
            //            record->columnized = TRUE;
        }
        if (enable_color_) {
            fdata->color_filter = NULL;
            //            record->colorized = TRUE;
        }
        buffer_free(&buf);
        return QVariant();	/* error reading the frame */
    }

    create_proto_tree = (color_filters_used() && enable_color_) ||
                        (have_custom_cols(cinfo) && dissect_columns);

    epan_dissect_init(&edt, cap_file_->epan,
                      create_proto_tree,
                      FALSE /* proto_tree_visible */);

    if (enable_color_)
        color_filters_prime_edt(&edt);
    if (dissect_columns)
        col_custom_prime_edt(&edt, cinfo);

    epan_dissect_run(&edt, &phdr, frame_tvbuff_new_buffer(fdata, &buf), fdata, cinfo);

    if (enable_color_)
        fdata->color_filter = color_filters_colorize_packet(&edt);

    if (dissect_columns) {
        /* "Stringify" non frame_data vals */
        epan_dissect_fill_in_columns(&edt, FALSE, FALSE /* fill_fd_columns */);

        //            for(col = 0; col < cinfo->num_cols; ++col) {
        //                    /* Skip columns based on frame_data because we already store those. */
        //                    if (!col_based_on_frame_data(cinfo, col))
        //                            packet_list_change_record(packet_list, record->physical_pos, col, cinfo);
        //            }
//        g_log(NULL, G_LOG_LEVEL_DEBUG, "d_c %d: %s", col_num, cinfo->col_data[col_num]);
    }

    //    if (dissect_columns)
    //            record->columnized = TRUE;
    //    if (enable_color_)
    //            record->colorized = TRUE;

    epan_dissect_cleanup(&edt);
    buffer_free(&buf);

    switch (role) {
    case Qt::DisplayRole:
        return record->data(col_num, cinfo);
        break;
    default:
        break;
    }
    return QVariant();
}
void RelatedPacketDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
                              const QModelIndex &index) const
{
    int en_w = option.fontMetrics.height() / 2;

    QStyleOptionViewItemV4 optv4 = option;
    QStyledItemDelegate::initStyleOption(&optv4, index);

    optv4.features |= QStyleOptionViewItemV4::HasDecoration;
    optv4.decorationSize.setHeight(1);
    optv4.decorationSize.setWidth(en_w);
    QStyledItemDelegate::paint(painter, optv4, index);

    const frame_data *fd;
    PacketListRecord *record = static_cast<PacketListRecord*>(index.internalPointer());
    if (!record || (fd = record->frameData()) == NULL) {
        return;
    }

    painter->save();

    if (QApplication::style()->objectName().contains("vista")) {
        // QWindowsVistaStyle::drawControl does this internally. Unfortunately there
        // doesn't appear to be a more general way to do this.
        optv4.palette.setColor(QPalette::All, QPalette::HighlightedText, optv4.palette.color(QPalette::Active, QPalette::Text));
    }

    QPalette::ColorGroup cg = optv4.state & QStyle::State_Enabled
                              ? QPalette::Normal : QPalette::Disabled;
    QColor fg;
    if (cg == QPalette::Normal && !(optv4.state & QStyle::State_Active))
        cg = QPalette::Inactive;
    if (optv4.state & QStyle::State_Selected) {
        fg = optv4.palette.color(cg, QPalette::HighlightedText);
    } else {
        fg = optv4.palette.color(cg, QPalette::Text);
    }
    qreal alpha = 0.20; // Arbitrary. Should arguably be a preference.

    // We draw in the same place more than once so we first draw on a
    // QImage at 100% opacity then draw that on our packet list item.
    QImage overlay = QImage(en_w * 2, optv4.rect.height(), QImage::Format_ARGB32_Premultiplied);
    QPainter op(&overlay);

    overlay.fill(Qt::transparent);
    op.setPen(fg);
    op.translate(en_w + 0.5, 0.5);
    op.setRenderHint(QPainter::Antialiasing, true);

    // The current decorations are based on what looked good and were easy
    // to code. W might want to improve them by drawing small dots or tick
    // marks for frames in the same conversation XOR draw a gap for unrelated
    // frames.
    if (first_frame_ > 0 && last_frame_ > 0 && first_frame_ != last_frame_) {
        int height = optv4.rect.height();
        if ((int) fd->num == first_frame_) {
            op.drawLine(0, height / 2, 0, height);
            op.drawLine(1, height / 2, en_w, height / 2);
        } else if ((int) fd->num > first_frame_ && (int) fd->num < last_frame_) {
            op.drawLine(0, 0, 0, height);
        } else if ((int) fd->num == last_frame_) {
            op.drawLine(0, 0, 0, height / 2);
            op.drawLine(1, height / 2, en_w, height / 2);
        }
    }
    if (related_frames_.contains(fd->num)) {
        op.setBrush(fg);
        op.drawEllipse(QPointF(0.0, optv4.rect.height() / 2), 2, 2);
    }

    painter->setOpacity(alpha);
    painter->drawImage(optv4.rect.x(), optv4.rect.y(), overlay);
    painter->restore();
}