地面站终端 App
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

637 lines
16 KiB

/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
* Qwt Widget Library
* Copyright (C) 1997 Josef Wilgen
* Copyright (C) 2002 Uwe Rathmann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the Qwt License, Version 1.0
*****************************************************************************/
// vim: expandtab
#include <qapplication.h>
#include <qmap.h>
#if QT_VERSION >= 0x040000
#include <qscrollbar.h>
#endif
#include "qwt_math.h"
#include "qwt_dyngrid_layout.h"
#include "qwt_legend_itemmanager.h"
#include "qwt_legend_item.h"
#include "qwt_legend.h"
class QwtLegend::PrivateData
{
public:
class LegendMap
{
public:
void insert(const QwtLegendItemManager *, QWidget *);
void remove(const QwtLegendItemManager *);
void remove(QWidget *);
void clear();
uint count() const;
inline const QWidget *find(const QwtLegendItemManager *) const;
inline QWidget *find(const QwtLegendItemManager *);
inline const QwtLegendItemManager *find(const QWidget *) const;
inline QwtLegendItemManager *find(const QWidget *);
const QMap<QWidget *, const QwtLegendItemManager *> &widgetMap() const;
QMap<QWidget *, const QwtLegendItemManager *> &widgetMap();
private:
QMap<QWidget *, const QwtLegendItemManager *> d_widgetMap;
QMap<const QwtLegendItemManager *, QWidget *> d_itemMap;
};
QwtLegend::LegendItemMode itemMode;
QwtLegend::LegendDisplayPolicy displayPolicy;
int identifierMode;
LegendMap map;
class LegendView;
LegendView *view;
};
#if QT_VERSION < 0x040000
#include <qscrollview.h>
class QwtLegend::PrivateData::LegendView: public QScrollView
{
public:
LegendView(QWidget *parent):
QScrollView(parent) {
setResizePolicy(Manual);
viewport()->setBackgroundMode(Qt::NoBackground); // Avoid flicker
contentsWidget = new QWidget(viewport());
addChild(contentsWidget);
}
void viewportResizeEvent(QResizeEvent *e) {
QScrollView::viewportResizeEvent(e);
// It's not safe to update the layout now, because
// we are in an internal update of the scrollview framework.
// So we delay the update by posting a LayoutHint.
QApplication::postEvent(contentsWidget,
new QEvent(QEvent::LayoutHint));
}
QWidget *contentsWidget;
};
#else // QT_VERSION >= 0x040000
#include <qscrollarea.h>
class QwtLegend::PrivateData::LegendView: public QScrollArea
{
public:
LegendView(QWidget *parent):
QScrollArea(parent) {
contentsWidget = new QWidget(this);
setWidget(contentsWidget);
setWidgetResizable(false);
setFocusPolicy(Qt::NoFocus);
}
virtual bool viewportEvent(QEvent *e) {
bool ok = QScrollArea::viewportEvent(e);
if ( e->type() == QEvent::Resize ) {
QEvent event(QEvent::LayoutRequest);
QApplication::sendEvent(contentsWidget, &event);
}
return ok;
}
QSize viewportSize(int w, int h) const {
const int sbHeight = horizontalScrollBar()->sizeHint().height();
const int sbWidth = verticalScrollBar()->sizeHint().width();
const int cw = contentsRect().width();
const int ch = contentsRect().height();
int vw = cw;
int vh = ch;
if ( w > vw )
vh -= sbHeight;
if ( h > vh ) {
vw -= sbWidth;
if ( w > vw && vh == ch )
vh -= sbHeight;
}
return QSize(vw, vh);
}
QWidget *contentsWidget;
};
#endif
void QwtLegend::PrivateData::LegendMap::insert(
const QwtLegendItemManager *item, QWidget *widget)
{
d_itemMap.insert(item, widget);
d_widgetMap.insert(widget, item);
}
void QwtLegend::PrivateData::LegendMap::remove(const QwtLegendItemManager *item)
{
QWidget *widget = d_itemMap[item];
d_itemMap.remove(item);
d_widgetMap.remove(widget);
}
void QwtLegend::PrivateData::LegendMap::remove(QWidget *widget)
{
const QwtLegendItemManager *item = d_widgetMap[widget];
d_itemMap.remove(item);
d_widgetMap.remove(widget);
}
void QwtLegend::PrivateData::LegendMap::clear()
{
/*
We can't delete the widgets in the following loop, because
we would get ChildRemoved events, changing d_itemMap, while
we are iterating.
*/
#if QT_VERSION < 0x040000
QValueList<QWidget *> widgets;
QMap<const QwtLegendItemManager *, QWidget *>::const_iterator it;
for ( it = d_itemMap.begin(); it != d_itemMap.end(); ++it )
widgets.append(it.data());
#else
QList<QWidget *> widgets;
QMap<const QwtLegendItemManager *, QWidget *>::const_iterator it;
for ( it = d_itemMap.begin(); it != d_itemMap.end(); ++it )
widgets.append(it.value());
#endif
d_itemMap.clear();
d_widgetMap.clear();
for ( int i = 0; i < (int)widgets.size(); i++ )
delete widgets[i];
}
uint QwtLegend::PrivateData::LegendMap::count() const
{
return d_itemMap.count();
}
inline const QWidget *QwtLegend::PrivateData::LegendMap::find(const QwtLegendItemManager *item) const
{
if ( !d_itemMap.contains((QwtLegendItemManager *)item) )
return NULL;
return d_itemMap[(QwtLegendItemManager *)item];
}
inline QWidget *QwtLegend::PrivateData::LegendMap::find(const QwtLegendItemManager *item)
{
if ( !d_itemMap.contains((QwtLegendItemManager *)item) )
return NULL;
return d_itemMap[(QwtLegendItemManager *)item];
}
inline const QwtLegendItemManager *QwtLegend::PrivateData::LegendMap::find(
const QWidget *widget) const
{
if ( !d_widgetMap.contains((QWidget *)widget) )
return NULL;
return d_widgetMap[(QWidget *)widget];
}
inline QwtLegendItemManager *QwtLegend::PrivateData::LegendMap::find(
const QWidget *widget)
{
if ( !d_widgetMap.contains((QWidget *)widget) )
return NULL;
return (QwtLegendItemManager *)d_widgetMap[(QWidget *)widget];
}
inline const QMap<QWidget *, const QwtLegendItemManager *> &
QwtLegend::PrivateData::LegendMap::widgetMap() const
{
return d_widgetMap;
}
inline QMap<QWidget *, const QwtLegendItemManager *> &
QwtLegend::PrivateData::LegendMap::widgetMap()
{
return d_widgetMap;
}
/*!
\param parent Parent widget
*/
QwtLegend::QwtLegend(QWidget *parent):
QFrame(parent)
{
setFrameStyle(NoFrame);
d_data = new QwtLegend::PrivateData;
d_data->itemMode = QwtLegend::ReadOnlyItem;
d_data->displayPolicy = QwtLegend::AutoIdentifier;
d_data->identifierMode = QwtLegendItem::ShowLine |
QwtLegendItem::ShowSymbol | QwtLegendItem::ShowText;
d_data->view = new QwtLegend::PrivateData::LegendView(this);
d_data->view->setFrameStyle(NoFrame);
QwtDynGridLayout *layout = new QwtDynGridLayout(
d_data->view->contentsWidget);
#if QT_VERSION < 0x040000
layout->setAutoAdd(true);
#endif
layout->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
d_data->view->contentsWidget->installEventFilter(this);
}
//! Destructor
QwtLegend::~QwtLegend()
{
delete d_data;
}
/*!
Set the legend display policy to:
\param policy Legend display policy
\param mode Identifier mode (or'd ShowLine, ShowSymbol, ShowText)
\sa displayPolicy, LegendDisplayPolicy
*/
void QwtLegend::setDisplayPolicy(LegendDisplayPolicy policy, int mode)
{
d_data->displayPolicy = policy;
if (-1 != mode)
d_data->identifierMode = mode;
QMap<QWidget *, const QwtLegendItemManager *> &map =
d_data->map.widgetMap();
QMap<QWidget *, const QwtLegendItemManager *>::iterator it;
for ( it = map.begin(); it != map.end(); ++it ) {
#if QT_VERSION < 0x040000
QwtLegendItemManager *item = (QwtLegendItemManager *)it.data();
#else
QwtLegendItemManager *item = (QwtLegendItemManager *)it.value();
#endif
if ( item )
item->updateLegend(this);
}
}
/*!
\return the legend display policy.
Default is LegendDisplayPolicy::Auto.
\sa setDisplayPolicy, LegendDisplayPolicy
*/
QwtLegend::LegendDisplayPolicy QwtLegend::displayPolicy() const
{
return d_data->displayPolicy;
}
void QwtLegend::setItemMode(LegendItemMode mode)
{
d_data->itemMode = mode;
}
QwtLegend::LegendItemMode QwtLegend::itemMode() const
{
return d_data->itemMode;
}
/*!
\return the IdentifierMode to be used in combination with
LegendDisplayPolicy::Fixed.
Default is ShowLine | ShowSymbol | ShowText.
*/
int QwtLegend::identifierMode() const
{
return d_data->identifierMode;
}
/*!
The contents widget is the only child of the viewport() and
the parent widget of all legend items.
*/
QWidget *QwtLegend::contentsWidget()
{
return d_data->view->contentsWidget;
}
QScrollBar *QwtLegend::horizontalScrollBar() const
{
return d_data->view->horizontalScrollBar();
}
QScrollBar *QwtLegend::verticalScrollBar() const
{
return d_data->view->verticalScrollBar();
}
/*!
The contents widget is the only child of the viewport() and
the parent widget of all legend items.
*/
const QWidget *QwtLegend::contentsWidget() const
{
return d_data->view->contentsWidget;
}
/*!
Insert a new item for a plot item
\param plotItem Plot item
\param legendItem New legend item
\note The parent of item will be changed to QwtLegend::contentsWidget()
*/
void QwtLegend::insert(const QwtLegendItemManager *plotItem, QWidget *legendItem)
{
if ( legendItem == NULL || plotItem == NULL )
return;
QWidget *contentsWidget = d_data->view->contentsWidget;
if ( legendItem->parent() != contentsWidget ) {
#if QT_VERSION >= 0x040000
legendItem->setParent(contentsWidget);
#else
legendItem->reparent(contentsWidget, QPoint(0, 0));
#endif
}
legendItem->show();
d_data->map.insert(plotItem, legendItem);
layoutContents();
if ( contentsWidget->layout() ) {
#if QT_VERSION >= 0x040000
contentsWidget->layout()->addWidget(legendItem);
#endif
// set tab focus chain
QWidget *w = NULL;
#if QT_VERSION < 0x040000
QLayoutIterator layoutIterator =
contentsWidget->layout()->iterator();
for ( QLayoutItem *item = layoutIterator.current();
item != 0; item = ++layoutIterator) {
#else
for (int i = 0; i < contentsWidget->layout()->count(); i++) {
QLayoutItem *item = contentsWidget->layout()->itemAt(i);
#endif
if ( w && item->widget() ) {
QWidget::setTabOrder(w, item->widget());
w = item->widget();
}
}
}
if ( parentWidget() && parentWidget()->layout() == NULL ) {
/*
updateGeometry() doesn't post LayoutRequest in certain
situations, like when we are hidden. But we want the
parent widget notified, so it can show/hide the legend
depending on its items.
*/
#if QT_VERSION < 0x040000
QApplication::postEvent(parentWidget(),
new QEvent(QEvent::LayoutHint));
#else
QApplication::postEvent(parentWidget(),
new QEvent(QEvent::LayoutRequest));
#endif
}
}
/*!
Find the widget that represents a plot item
\param plotItem Plot item
\return Widget on the legend, or NULL
*/
QWidget *QwtLegend::find(const QwtLegendItemManager *plotItem) const
{
return d_data->map.find(plotItem);
}
/*!
Find the widget that represents a plot item
\param plotItem Plot item
\return Widget on the legend, or NULL
*/
QwtLegendItemManager *QwtLegend::find(const QWidget *legendItem) const
{
return d_data->map.find(legendItem);
}
/*!
Find the corresponding item for a plotItem and remove it
from the item list.
\param plotItem Plot item
*/
void QwtLegend::remove(const QwtLegendItemManager *plotItem)
{
QWidget *legendItem = d_data->map.find(plotItem);
d_data->map.remove(legendItem);
delete legendItem;
}
//! Remove all items.
void QwtLegend::clear()
{
#if QT_VERSION < 0x040000
bool doUpdate = isUpdatesEnabled();
#else
bool doUpdate = updatesEnabled();
#endif
setUpdatesEnabled(false);
d_data->map.clear();
setUpdatesEnabled(doUpdate);
update();
}
//! Return a size hint.
QSize QwtLegend::sizeHint() const
{
QSize hint = d_data->view->contentsWidget->sizeHint();
hint += QSize(2 * frameWidth(), 2 * frameWidth());
return hint;
}
/*!
\return The preferred height, for the width w.
\param width Width
*/
int QwtLegend::heightForWidth(int width) const
{
width -= 2 * frameWidth();
int h = d_data->view->contentsWidget->heightForWidth(width);
#if QT_VERSION < 0x040000
// Asking the layout is the default implementation in Qt4
if ( h <= 0 ) {
QLayout *l = d_data->view->contentsWidget->layout();
if ( l && l->hasHeightForWidth() )
h = l->heightForWidth(width);
}
#endif
if ( h >= 0 )
h += 2 * frameWidth();
return h;
}
/*!
Adjust contents widget and item layout to the size of the viewport().
*/
void QwtLegend::layoutContents()
{
const QSize visibleSize = d_data->view->viewport()->size();
const QLayout *l = d_data->view->contentsWidget->layout();
if ( l && l->inherits("QwtDynGridLayout") ) {
const QwtDynGridLayout *tl = (const QwtDynGridLayout *)l;
const int minW = int(tl->maxItemWidth()) + 2 * tl->margin();
int w = qwtMax(visibleSize.width(), minW);
int h = qwtMax(tl->heightForWidth(w), visibleSize.height());
const int vpWidth = d_data->view->viewportSize(w, h).width();
if ( w > vpWidth ) {
w = qwtMax(vpWidth, minW);
h = qwtMax(tl->heightForWidth(w), visibleSize.height());
}
d_data->view->contentsWidget->resize(w, h);
#if QT_VERSION < 0x040000
d_data->view->resizeContents(w, h);
#endif
}
}
/*
Filter layout related events of QwtLegend::contentsWidget().
\param o Object to be filtered
\param e Event
*/
bool QwtLegend::eventFilter(QObject *o, QEvent *e)
{
if ( o == d_data->view->contentsWidget ) {
switch(e->type()) {
case QEvent::ChildRemoved: {
const QChildEvent *ce = (const QChildEvent *)e;
if ( ce->child()->isWidgetType() )
d_data->map.remove((QWidget *)ce->child());
break;
}
#if QT_VERSION < 0x040000
case QEvent::LayoutHint:
#else
case QEvent::LayoutRequest:
#endif
{
layoutContents();
break;
}
#if QT_VERSION < 0x040000
case QEvent::Resize: {
updateGeometry();
break;
}
#endif
default:
break;
}
}
return QFrame::eventFilter(o, e);
}
//! Return true, if there are no legend items.
bool QwtLegend::isEmpty() const
{
return d_data->map.count() == 0;
}
//! Return the number of legend items.
uint QwtLegend::itemCount() const
{
return d_data->map.count();
}
#if QT_VERSION < 0x040000
QValueList<QWidget *> QwtLegend::legendItems() const
#else
QList<QWidget *> QwtLegend::legendItems() const
#endif
{
const QMap<QWidget *, const QwtLegendItemManager *> &map =
d_data->map.widgetMap();
#if QT_VERSION < 0x040000
QValueList<QWidget *> list;
#else
QList<QWidget *> list;
#endif
QMap<QWidget *, const QwtLegendItemManager *>::const_iterator it;
for ( it = map.begin(); it != map.end(); ++it )
list += it.key();
return list;
}
/*!
Resize event
\param e Event
*/
void QwtLegend::resizeEvent(QResizeEvent *e)
{
QFrame::resizeEvent(e);
d_data->view->setGeometry(contentsRect());
}