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.

508 lines
19 KiB

/***************************************************************************
ksgraphwizard.cpp - description
-------------------
begin : Thu Mar 14 2002
copyright : (C) 2002 by kamil
email : kamil@localhost.localdomain
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#include "ksgraphwizard.h"
#include "../ksmatrix.h"
#include "../ksworkbook.h"
#include "../ksglobalmatrixlist.h"
#include "../ksglobalsettings.h"
#include "../ksmatrixeditor.h"
#include "../ksdatasymbolfactory.h"
#include "../kscommands.h"
#include "../widgets/qsplotview.h"
#include "../widgets/qscurve.h"
#include "../widgets/qsimage.h"
#include "../widgets/qscontour.h"
#include "../widgets/qssurface.h"
#include "../widgets/qsfigure.h"
#include "../widgets/qsconsole.h"
#include "../widgets/qsaxes2d.h"
#include "../widgets/qsaxes3d.h"
#include "../formula/mpformula.h"
#include "kschannellist.h"
#include <qradiobutton.h>
#include <qlistbox.h>
#include <qpixmap.h>
#include <qpushbutton.h>
#include <qlabel.h>
#include <qtextedit.h>
#include <qcheckbox.h>
#include <qevent.h>
#include <qpainter.h>
//-------------------------------------------------------------------------//
KSGraphSubtypeItem::KSGraphSubtypeItem( QIconView *parent, KSDataObjectFactory::DataObject objectType, const QString& title, const QString& icon )
: QIconViewItem( parent, title, QPixmap( KSGlobalSettings::picturePath()+"/"+icon ) )
{
m_object_type = objectType;
}
//-------------------------------------------------------------------------//
KSGraphSubtypeItem::~KSGraphSubtypeItem()
{
}
//-------------------------------------------------------------------------//
QWidget *KSGraphSubtypeItem::additionalPage( QWidget *parent )
// not implemented
{
return NULL;
}
//-------------------------------------------------------------------------//
void KSGraphSubtypeItem::initChannels( KSGraphInfo *info )
{
int channels = KSDataObjectFactory::channelNumber( m_object_type );
info->resize( channels );
for( int i=0; i<channels; i++ ) {
info->at(i).m_name = KSDataObjectFactory::channelNameFactory( m_object_type, i );
info->at(i).m_description = KSDataObjectFactory::channelDescFactory( m_object_type, i );
}
}
//-------------------------------------------------------------------------//
QSAxesChild *KSGraphSubtypeItem::createObject( QSAxes *parent )
// it must be reimplemented
{
return NULL;
}
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
class KSGraphCurveItem : public KSGraphSubtypeItem
{
public:
KSGraphCurveItem( QIconView *parent ) : KSGraphSubtypeItem( parent, KSDataObjectFactory::ObjectCurve, QObject::tr("Curve"), "graph_xyplot.png" ) {}
~KSGraphCurveItem() {}
virtual QSAxesChild *createObject( QSAxes *parent ) { QSCurve *result = new QSCurve(parent); return result; }
};
//-------------------------------------------------------------------------//
class KSGraphImageItem : public KSGraphSubtypeItem
{
public:
KSGraphImageItem( QIconView *parent ) : KSGraphSubtypeItem( parent, KSDataObjectFactory::ObjectImage, QObject::tr("Pixmap"), "graph_image.png" ) {}
~KSGraphImageItem() {}
virtual QSAxesChild *createObject( QSAxes *parent ) { QSImage *result = new QSImage(parent); return result; }
};
//-------------------------------------------------------------------------//
class KSGraphGriddedContourItem : public KSGraphSubtypeItem
{
public:
KSGraphGriddedContourItem( QIconView *parent ) : KSGraphSubtypeItem( parent, KSDataObjectFactory::ObjectGriddedContour, QObject::tr("Gridded contour"), "graph_contour.png" ) {}
~KSGraphGriddedContourItem() {}
virtual QSAxesChild *createObject( QSAxes *parent ) { QSGriddedContour *result = new QSGriddedContour(parent); return result; }
};
//-------------------------------------------------------------------------//
class KSGraphNonGriddedContourItem : public KSGraphSubtypeItem
{
public:
KSGraphNonGriddedContourItem( QIconView *parent ) : KSGraphSubtypeItem( parent, KSDataObjectFactory::ObjectNonGriddedContour, QObject::tr("Non-gridded contour"), "graph_ngcontour.png" ) {}
~KSGraphNonGriddedContourItem() {}
virtual QSAxesChild *createObject( QSAxes *parent ) { QSNonGriddedContour *result = new QSNonGriddedContour(parent); return result; }
virtual void initChannels( KSGraphInfo *info ) {
KSGraphSubtypeItem::initChannels( info );
info->at(QSNonGriddedContour::Triangles).m_use_formula=true;
info->at(QSNonGriddedContour::Triangles).m_formula="delunay(x,y)";
}
};
//-------------------------------------------------------------------------//
class KSGraphSurfaceItem : public KSGraphSubtypeItem
{
public:
KSGraphSurfaceItem( QIconView *parent ) : KSGraphSubtypeItem( parent, KSDataObjectFactory::ObjectSurface, QObject::tr("Surface"), "graph_surface.png" ) {}
~KSGraphSurfaceItem() {}
virtual QSAxesChild *createObject( QSAxes *parent ) { QSSurface *result = new QSSurface(parent); return result; }
};
//-------------------------------------------------------------------------//
class KSGraphNonGriddedSurfaceItem : public KSGraphSubtypeItem
{
public:
KSGraphNonGriddedSurfaceItem( QIconView *parent ) : KSGraphSubtypeItem( parent, KSDataObjectFactory::ObjectFigure, QObject::tr("Non-gridded surface"), "graph_ngsurface.png" ) {}
~KSGraphNonGriddedSurfaceItem() {}
virtual QSAxesChild *createObject( QSAxes *parent ) { QSFigure *result = new QSFigure(parent); return result; }
virtual void initChannels( KSGraphInfo *info ) {
KSGraphSubtypeItem::initChannels( info );
info->at(QSFigure::VTableI).m_use_formula=true;
info->at(QSFigure::VTableI).m_formula="delunay(x,y)";
}
};
//-------------------------------------------------------------------------//
class KSGraphFigureItem : public KSGraphSubtypeItem
{
public:
KSGraphFigureItem( QIconView *parent ) : KSGraphSubtypeItem( parent, KSDataObjectFactory::ObjectFigure, QObject::tr("Figure"), "graph_figure.png" ) {}
~KSGraphFigureItem() {}
virtual QSAxesChild *createObject( QSAxes *parent ) { QSFigure *result = new QSFigure(parent); return result; }
};
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
KSGraphWizard::KSGraphWizard( QSPlotView *view, KSWorkbook *workbook, QWidget *parent, const char *name )
: KSGraphWizardInterf(parent,name,true)
{
m_view = view;
m_workbook = workbook;
m_sheet_editor = NULL; // select data range on it
m_preview_axes = NULL;
m_new_axes = NULL;
m_new_dataset = NULL;
m_watch_data_page = true;
for ( int i=0; i<pageCount(); i++ ) setHelpEnabled( QWizard::page(i), false );
if ( m_view->activeAxes() ) selectedAxes->setChecked( TRUE ); else { newAxes2D->setChecked( TRUE ); selectedAxes->setEnabled( false ); }
worksheetList->addColumn( tr("Sheets"), 95 );
worksheetList->addColumn( tr(""), 95 );
worksheetList->addColumn( tr(""), 50 );
worksheetList->setDataObject( m_workbook->sheets(), false, 0, false );
connect( graphType, SIGNAL(highlighted(int)), this, SLOT(slot_graph_type_changed(int)) );
connect( graphType, SIGNAL(selectionChanged()), this, SLOT(slot_page_type_changed()) );
connect( graphSubtype, SIGNAL(selectionChanged()), this, SLOT(slot_page_type_changed()) );
connect( worksheetList, SIGNAL(selectionChanged()), this, SLOT(slot_page_type_changed()) );
connect( channelList, SIGNAL(highlighted(int)), this, SLOT(slot_channel_selected(int)) );
connect( clearChannel, SIGNAL(clicked()), this, SLOT(slot_clear_channel()) );
connect( useFormula, SIGNAL(stateChanged(int)), this, SLOT(slot_channel_data_changed()) );
connect( formulaString, SIGNAL(textChanged()), this, SLOT(slot_channel_data_changed()) );
graphSubtype->clear();
setNextEnabled( QWizard::page(1), false );
setFinishEnabled( QWizard::page(3), true );
sheetEditorPlace->installEventFilter( this );
previewPlace->installEventFilter( this );
}
//-------------------------------------------------------------------------//
KSGraphWizard::~KSGraphWizard()
{
delete m_sheet_editor;
clear_preview();
}
//-------------------------------------------------------------------------//
bool KSGraphWizard::eventFilter( QObject *object, QEvent *e )
{
if ( object == sheetEditorPlace && e->type() == QEvent::Resize ) {
if ( m_sheet_editor && m_sheet_editor->widget() )
m_sheet_editor->widget()->resize( sheetEditorPlace->size() );
}
else if ( object == previewPlace && e->type() == QEvent::Paint ) {
if ( m_preview_axes ) {
QPainter painter( previewPlace );
m_preview_axes->stop();
m_preview_axes->setCanvasRect( QSRectf(60,40,previewPlace->width()-120,previewPlace->height()-80) );
m_preview_axes->paintPlot( &painter, 72.0, false );
return true;
}
}
return false;
}
//-------------------------------------------------------------------------//
void KSGraphWizard::showPage( QWidget *page )
{
switch( indexOf(page) ) {
// case 0: show_page_into(); break;
// case 1: show_page_type(); break;
case 2: show_page_data(); break;
case 3: show_page_finish(); break;
}
QWizard::showPage( page );
}
//-------------------------------------------------------------------------//
void KSGraphWizard::slot_page_type_changed()
// state of the widgets on the type page has changed
// check if we can enable the next button
{
if ( graphType->currentItem() >= 0 && graphSubtype->currentItem() && worksheetList->selectedItem() )
setNextEnabled( QWizard::page(1), true ); else setNextEnabled( QWizard::page(1), false );
}
//-------------------------------------------------------------------------//
void KSGraphWizard::slot_graph_type_changed( int index )
// type of the graph has changed - show all available subtypes for this type
{
graphSubtype->clear();
switch( index ) {
// XY plot
case 0:
(void )new KSGraphCurveItem( graphSubtype );
break;
// Pixmap
case 1:
(void )new KSGraphImageItem( graphSubtype );
break;
// Contour
case 2:
(void )new KSGraphGriddedContourItem( graphSubtype );
(void )new KSGraphNonGriddedContourItem( graphSubtype );
break;
// Surface
case 3:
(void )new KSGraphSurfaceItem( graphSubtype );
(void )new KSGraphNonGriddedSurfaceItem( graphSubtype );
break;
// Figure
case 4:
(void )new KSGraphFigureItem( graphSubtype );
break;
}
slot_page_type_changed();
}
//-------------------------------------------------------------------------//
void KSGraphWizard::show_page_data()
{
// delete preview object ( if back was clicked and we moved from the finish page )
clear_preview();
// create channel list
KSGraphSubtypeItem *m_graph_subtype = dynamic_cast<KSGraphSubtypeItem*>(graphSubtype->currentItem());
m_graph_subtype->initChannels( &m_graph_info );
channelList->clear();
for( int i=0; i<m_graph_info.size(); i++ ) channelList->insertItem( m_graph_info.at(i).m_name );
slot_channel_selected( -1 );
}
//-------------------------------------------------------------------------//
void KSGraphWizard::slot_channel_selected( int index )
{
set_watch_data_page( false );
// channel was selected - show the editor with the worksheet and allow user to select a data range
if ( index >= 0 ) {
KSGraphChannelInfo channel = m_graph_info.at(index);
// fill all fields
channelDescription->setText( channel.m_description );
formulaString->setText( channel.m_formula );
useFormula->setChecked( channel.m_use_formula );
// create editor
QSData *data_object = channel.m_sheet ? channel.m_sheet : worksheetList->selected()->dataObject();
if ( m_sheet_editor == NULL || m_sheet_editor->editedMatrix() != data_object->matrix(0) ) {
delete m_sheet_editor; m_sheet_editor = NULL;
m_sheet_editor = KSDataObjectFactory::createEditor( m_workbook, data_object, 0, sheetEditorPlace );
//
// this is a little trick !
//
connect( m_sheet_editor->widget(), SIGNAL(selectionChanged()), this, SLOT(slot_channel_data_changed()) );
}
// initialize editor
m_sheet_editor->setSelectionRange( channel.m_selection );
m_sheet_editor->setEditorContentsPos( channel.m_editor_pos );
m_sheet_editor->widget()->resize( sheetEditorPlace->size() );
m_sheet_editor->widget()->show();
} else {
channelDescription->setText( QString::null );
formulaString->setText( QString::null );
useFormula->setChecked( false );
delete m_sheet_editor; m_sheet_editor = NULL;
}
set_watch_data_page( true );
}
//-------------------------------------------------------------------------//
void KSGraphWizard::slot_clear_channel()
// clear channel data button was clicked
{
int curr_channel = channelList->currentItem();
if ( curr_channel >= 0 ) {
m_graph_info.at(curr_channel).m_use_formula = false;
m_graph_info.at(curr_channel).m_sheet = NULL;
m_graph_info.at(curr_channel).m_selection = QRect();
m_graph_info.at(curr_channel).m_editor_pos = QPoint();
slot_channel_selected( curr_channel );
}
}
//-------------------------------------------------------------------------//
void KSGraphWizard::slot_channel_data_changed()
// state of the data panel was changed ( button clicked, text entered, selection changed etc... )
// remembercurrent settings for the selected channel
{
if ( !m_watch_data_page ) return;
int curr_channel = channelList->currentItem();
if ( curr_channel >= 0 ) {
if ( m_sheet_editor && !m_sheet_editor->selectionRange().isEmpty() ) {
if ( !m_graph_info.at(curr_channel).m_sheet )
m_graph_info.at(curr_channel).m_sheet = dynamic_cast<KSSheet*>(worksheetList->selected()->dataObject());
m_graph_info.at(curr_channel).m_selection = m_sheet_editor->selectionRange();
}
if ( m_sheet_editor ) m_graph_info.at(curr_channel).m_editor_pos = m_sheet_editor->editorContentsPos();
m_graph_info.at(curr_channel).m_formula = formulaString->text();
m_graph_info.at(curr_channel).m_use_formula = useFormula->isChecked();
}
}
//-------------------------------------------------------------------------//
void KSGraphWizard::show_page_finish()
// user clicked next and we enter the finish page - show the preview
{
clear_preview();
// create preview
KSGraphSubtypeItem *m_graph_subtype = dynamic_cast<KSGraphSubtypeItem*>(graphSubtype->currentItem());
if ( selectedAxes->isChecked() ) {
m_preview_axes = m_view->activeAxes();
}
else if ( newAxes2D->isChecked() ) {
m_new_axes = new QSAxes2D();
m_preview_axes = m_new_axes;
}
else if ( newAxes3D->isChecked() ) {
m_new_axes = new QSAxes3D();
m_preview_axes = m_new_axes;
}
m_new_dataset = m_graph_subtype->createObject( m_preview_axes );
create_data( m_new_dataset );
m_preview_axes->plotAdd( dynamic_cast<QSPlot*>(m_new_dataset) );
}
//-------------------------------------------------------------------------//
void KSGraphWizard::create_data( QSData *new_object )
// create dataset from channel data
{
for( int i=0; i<new_object->channelCount(); i++ ) {
KSGraphChannelInfo channel = m_graph_info.at(i);
if ( channel.m_use_formula ) {
KSMatrixFormula *new_matrix = new KSMatrixFormula();
new_matrix->setFormula( channel.m_formula );
new_object->setMatrix( i, new_matrix );
}
else if ( !channel.m_selection.isEmpty() ) {
KSSheet *sheet = channel.m_sheet ? channel.m_sheet : dynamic_cast<KSSheet*>(worksheetList->selected()->dataObject());
KSMatrixWorksheetCellRange *new_matrix = new KSMatrixWorksheetCellRange( m_workbook );
new_matrix->setWorksheet( m_workbook->sheets()->sheetFind( sheet ) );
new_matrix->setRowFrom( channel.m_selection.top() );
new_matrix->setColFrom( channel.m_selection.left() );
if ( channel.m_selection.bottom() == sheet->matrix(0)->rows()-1 ) new_matrix->setRowTo( -1 );
else new_matrix->setRowTo( channel.m_selection.bottom() );
if ( channel.m_selection.right() == sheet->matrix(0)->cols()-1 ) new_matrix->setColTo( -1 );
else new_matrix->setColTo( channel.m_selection.right() );
new_object->setMatrix( i, new_matrix );
}
}
// recalculate all formulas
for( int i=0; i<new_object->channelCount(); i++ ) {
KSMatrixFormula *formula_matrix = dynamic_cast<KSMatrixFormula*>(new_object->matrix(i));
if ( formula_matrix ) {
MPFactoryList factory( new KSDataSymbolFactory( m_workbook, formula_matrix->dataObject() ) );
MPFormulaError error;
formula_matrix->init( error, &factory );
if ( error.hasError() ) QSConsole::write( QObject::tr("Error parsing formula :")+formula_matrix->formula()+"<br>"+error.message() );
}
}
}
//-------------------------------------------------------------------------//
void KSGraphWizard::accept()
// user clicked ok - add objects to the workbook.
{
apply_dataset();
QWizard::accept();
}
//-------------------------------------------------------------------------//
void KSGraphWizard::clear_preview()
// delete object ( which was created for a preview )
{
if ( m_new_dataset ) m_new_dataset->parentAxes()->plotRemove( dynamic_cast<QSPlot*>(m_new_dataset) );
m_preview_axes = NULL;
delete m_new_dataset; m_new_dataset = NULL;
delete m_new_axes; m_new_axes = NULL;
}
//-------------------------------------------------------------------------//
void KSGraphWizard::apply_dataset()
// add object to the workbook
{
m_preview_axes = NULL;
if ( m_new_axes ) {
m_workbook->execute( new KSCmdAddCObject( m_new_axes->shadowObject(), m_view->currentPage()->objects() ) );
m_new_axes = NULL;
m_new_dataset = NULL;
}
else if ( m_new_dataset ) {
m_new_dataset->parentAxes()->plotRemove( dynamic_cast<QSPlot*>(m_new_dataset) );
m_workbook->execute( new KSCmdAddDataset(dynamic_cast<QSPlot*>(m_new_dataset)) );
m_new_dataset = NULL;
}
}
//-------------------------------------------------------------------------//
void KSGraphWizard::set_watch_data_page( bool enabled )
{
m_watch_data_page = enabled;
}