Salome HOME
Added "Replot" in method "setBackgroundColor"
[modules/gui.git] / src / Plot2d / Plot2d_ViewFrame.cxx
1 #include "Plot2d_ViewFrame.h"
2
3 #include "Plot2d_Prs.h"
4 #include "Plot2d_Curve.h"
5 #include "Plot2d_FitDataDlg.h"
6 #include "Plot2d_ViewWindow.h"
7 #include "Plot2d_SetupViewDlg.h"
8
9 #include "SUIT_Tools.h"
10 #include "SUIT_FileDlg.h"
11 #include "SUIT_Session.h"
12 #include "SUIT_MessageBox.h"
13 #include "SUIT_ResourceMgr.h"
14
15 //#include "utilities.h"
16
17 #include "qapplication.h"
18 #include <qtoolbar.h>
19 #include <qtoolbutton.h>
20 #include <qcursor.h>
21 #include <qcolordialog.h>
22 #include <qptrlist.h>
23 #include <qlayout.h>
24 #include <qmap.h>
25
26 #include <qwt_math.h>
27 #include <qwt_plot_canvas.h>
28 #include <iostream.h>
29 #include <stdlib.h>
30
31 //#include "utilities.h"
32
33 #define DEFAULT_LINE_WIDTH     0     // (default) line width
34 #define DEFAULT_MARKER_SIZE    9     // default marker size
35 #define MIN_RECT_SIZE          11    // min sensibility area size
36
37 const char* imageZoomCursor[] = { 
38 "32 32 3 1",
39 ". c None",
40 "a c #000000",
41 "# c #ffffff",
42 "................................",
43 "................................",
44 ".#######........................",
45 "..aaaaaaa.......................",
46 "................................",
47 ".............#####..............",
48 "...........##.aaaa##............",
49 "..........#.aa.....a#...........",
50 ".........#.a.........#..........",
51 ".........#a..........#a.........",
52 "........#.a...........#.........",
53 "........#a............#a........",
54 "........#a............#a........",
55 "........#a............#a........",
56 "........#a............#a........",
57 ".........#...........#.a........",
58 ".........#a..........#a.........",
59 ".........##.........#.a.........",
60 "........#####.....##.a..........",
61 ".......###aaa#####.aa...........",
62 "......###aa...aaaaa.......#.....",
63 ".....###aa................#a....",
64 "....###aa.................#a....",
65 "...###aa...............#######..",
66 "....#aa.................aa#aaaa.",
67 ".....a....................#a....",
68 "..........................#a....",
69 "...........................a....",
70 "................................",
71 "................................",
72 "................................",
73 "................................"};
74
75 const char* imageCrossCursor[] = { 
76   "32 32 3 1",
77   ". c None",
78   "a c #000000",
79   "# c #ffffff",
80   "................................",
81   "................................",
82   "................................",
83   "................................",
84   "................................",
85   "................................",
86   "................................",
87   "...............#................",
88   "...............#a...............",
89   "...............#a...............",
90   "...............#a...............",
91   "...............#a...............",
92   "...............#a...............",
93   "...............#a...............",
94   "...............#a...............",
95   ".......#################........",
96   "........aaaaaaa#aaaaaaaaa.......",
97   "...............#a...............",
98   "...............#a...............",
99   "...............#a...............",
100   "...............#a...............",
101   "...............#a...............",
102   "...............#a...............",
103   "...............#a...............",
104   "................a...............",
105   "................................",
106   "................................",
107   "................................",
108   "................................",
109   "................................",
110   "................................",
111   "................................"};
112   
113
114 QPixmap zoomPixmap(imageZoomCursor);
115 QPixmap globalPanPixmap(imageCrossCursor);
116
117 QCursor panCursor(Qt::SizeAllCursor);
118 QCursor zoomCursor(zoomPixmap);
119 QCursor glPanCursor(globalPanPixmap);
120
121 //=================================================================================
122 // Plot2d_ViewFrame implementation
123 //=================================================================================
124
125 /*!
126   Constructor
127 */
128 Plot2d_ViewFrame::Plot2d_ViewFrame( QWidget* parent, const QString& title )
129      : QWidget (parent, title, 0),
130        myOperation( NoOpId ), 
131        myCurveType( 1 ), 
132        myShowLegend( true ), myLegendPos( 1 ),
133        myMarkerSize( DEFAULT_MARKER_SIZE ),
134        myTitle( "" ), myXTitle( "" ), myYTitle( "" ), myY2Title( "" ),
135        myBackground( white ),
136        myTitleEnabled( true ), myXTitleEnabled( true ),
137        myYTitleEnabled( true ), myY2TitleEnabled (true),
138        myXGridMajorEnabled( true ), myYGridMajorEnabled( true ), myY2GridMajorEnabled( true ), 
139        myXGridMinorEnabled( false ), myYGridMinorEnabled( false ), myY2GridMinorEnabled( false ),
140        myXGridMaxMajor( 8 ), myYGridMaxMajor( 8 ), myY2GridMaxMajor( 8 ),
141        myXGridMaxMinor( 5 ), myYGridMaxMinor( 5 ), myY2GridMaxMinor( 5 ),
142        myXMode( 0 ), myYMode( 0 ), mySecondY( false )
143 {
144   /* Plot 2d View */
145   QGridLayout* aLayout = new QGridLayout( this ); 
146   myPlot = new Plot2d_Plot2d( this );
147   aLayout->addWidget( myPlot, 0, 0);
148
149 //  createActions();
150
151   connect( myPlot, SIGNAL( plotMouseMoved( const QMouseEvent& ) ),
152      this,   SLOT( plotMouseMoved( const QMouseEvent& ) ) );
153   connect( myPlot, SIGNAL( plotMousePressed( const QMouseEvent& ) ),
154      this,   SLOT( plotMousePressed( const QMouseEvent& ) ) );
155   connect( myPlot, SIGNAL( plotMouseReleased( const QMouseEvent& ) ),
156      this,   SLOT( plotMouseReleased( const QMouseEvent& ) ) );
157   //connect( myPlot, SIGNAL( legendClicked( long ) ),
158   //   this,   SLOT( onLegendClicked( long ) ) );
159
160   /* Initial Setup - get from the preferences */
161   readPreferences();
162
163   myPlot->setMargin( 5 );
164   setCurveType( myCurveType, false );
165   setXGrid( myXGridMajorEnabled, myXGridMaxMajor, myXGridMinorEnabled, myXGridMaxMinor, false );
166   setYGrid( myYGridMajorEnabled, myYGridMaxMajor, myYGridMinorEnabled, myYGridMaxMinor,
167             myY2GridMajorEnabled, myY2GridMaxMajor, myY2GridMinorEnabled, myY2GridMaxMinor, false );
168
169   setTitle( myTitleEnabled,  myTitle,  MainTitle, false );
170   setTitle( myXTitleEnabled, myXTitle, XTitle, false );
171   setTitle( myYTitleEnabled, myYTitle, YTitle, false );
172
173   if (mySecondY)
174     setTitle( myY2TitleEnabled, myY2Title, Y2Title, false );
175   setHorScaleMode( myXMode, false );
176   setVerScaleMode( myYMode, false );
177   setBackgroundColor( myBackground );
178   setLegendPos( myLegendPos );
179   showLegend( myShowLegend, false );
180   myPlot->replot();
181
182   if ( parent ) {
183     resize( (int)(0.8 * parent->width()), (int)(0.8 * parent->height()) );
184   }
185   QwtDiMap xMap = myPlot->canvasMap( QwtPlot::xBottom );
186   QwtDiMap yMap = myPlot->canvasMap( QwtPlot::yLeft );
187   myXDistance = xMap.d2() - xMap.d1();
188   myYDistance = yMap.d2() - yMap.d1();
189   myYDistance2 = 0;
190   if (mySecondY) {
191     QwtDiMap yMap2 = myPlot->canvasMap( QwtPlot::yRight );
192     myYDistance2 = yMap2.d2() - yMap2.d1();
193   }
194 }
195 /*!
196   Destructor
197 */
198 Plot2d_ViewFrame::~Plot2d_ViewFrame()
199 {
200 }
201 /*!
202   Gets window's central widget
203 */
204 QWidget* Plot2d_ViewFrame::getViewWidget()
205 {
206   return (QWidget*)myPlot;
207 }
208 /*!
209   Actually this method just re-displays all curves which are presented in the viewer
210 */
211 void Plot2d_ViewFrame::DisplayAll()
212 {
213   QList<Plot2d_Curve> clist;
214   getCurves( clist );
215   for ( int i = 0; i < (int)clist.count(); i++ ) {
216     updateCurve( clist.at( i ), false );
217   }
218   myPlot->replot();
219 }
220 /*!
221    Removes all curves from the view
222 */
223 void Plot2d_ViewFrame::EraseAll() 
224 {
225   myPlot->clear();
226   myCurves.clear();
227   myPlot->replot();
228 }
229 /*!
230   Redraws viewframe contents
231 */
232 void Plot2d_ViewFrame::Repaint()
233 {
234   myPlot->replot();
235 }
236 /*!
237   Display presentation
238 */
239 void Plot2d_ViewFrame::Display( const Plot2d_Prs* prs )
240 {
241   if ( !prs || prs->IsNull() )
242     return;
243
244   if (prs->isSecondY()) {
245     myPlot->enableAxis(QwtPlot::yRight, true);
246     mySecondY = true;
247   }
248   else {
249     myPlot->enableAxis(QwtPlot::yRight, false);
250     mySecondY = false;
251   }
252
253   // display all curves from presentation
254   curveList aCurves = prs->getCurves();
255   displayCurves( aCurves );
256   setXGrid( myXGridMajorEnabled, myXGridMaxMajor, myXGridMinorEnabled, myXGridMaxMinor, true );
257   setYGrid( myYGridMajorEnabled, myYGridMaxMajor, myYGridMinorEnabled, myYGridMaxMinor,
258             myY2GridMajorEnabled, myY2GridMaxMajor, myY2GridMinorEnabled, myY2GridMaxMinor, true );
259 }
260
261 /*!
262   Erase presentation
263 */
264 void Plot2d_ViewFrame::Erase( const Plot2d_Prs* prs, const bool )
265 {
266   if ( !prs || prs->IsNull() )
267     return;
268
269   // erase all curves from presentation
270   curveList aCurves = prs->getCurves();
271   eraseCurves( aCurves );
272 }
273
274 /*!
275   Sets title
276 */
277 void Plot2d_ViewFrame::setTitle( const QString& title )
278 {
279   setTitle( myTitleEnabled, title, MainTitle, true );
280 }
281
282 /*!
283   Reads Plot2d view settings from the preferences
284 */
285 void Plot2d_ViewFrame::readPreferences()
286 {
287   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
288
289   myCurveType = resMgr->integerValue( "Plot2d", "CurveType", myCurveType );
290   if ( myCurveType < 1 || myCurveType > 2 )
291     myCurveType = 1;
292   myShowLegend = resMgr->booleanValue( "Plot2d", "ShowLegend", myShowLegend );
293   myLegendPos = resMgr->integerValue( "Plot2d", "LegendPos", myLegendPos );
294   myMarkerSize = resMgr->integerValue( "Plot2d", "MarkerSize", myMarkerSize );
295   myBackground = resMgr->colorValue( "Plot2d", "Background", myBackground );
296
297   myTitleEnabled = resMgr->booleanValue( "Plot2d", "ShowTitle", myTitleEnabled );
298   myXTitleEnabled = resMgr->booleanValue( "Plot2d", "ShowHorTitle", myXTitleEnabled );
299   myYTitleEnabled = resMgr->booleanValue( "Plot2d", "ShowVerLeftTitle", myYTitleEnabled );
300   myY2TitleEnabled = resMgr->booleanValue( "Plot2d", "ShowVerRightTitle", myY2TitleEnabled );
301
302   myXGridMajorEnabled = resMgr->booleanValue( "Plot2d", "EnableHorMajorGrid", myXGridMajorEnabled );
303   myYGridMajorEnabled = resMgr->booleanValue( "Plot2d", "EnableVerMajorGrid", myYGridMajorEnabled );
304   myY2GridMajorEnabled = resMgr->booleanValue( "Plot2d", "EnableRightVerMajorGrid", myY2GridMajorEnabled );
305
306   myXGridMinorEnabled = resMgr->booleanValue( "Plot2d", "EnableHorMinorGrid", myXGridMinorEnabled );
307   myYGridMinorEnabled = resMgr->booleanValue( "Plot2d", "EnableVerMinorGrid", myYGridMinorEnabled );
308   myY2GridMinorEnabled = resMgr->booleanValue( "Plot2d", "EnableRightVerMinorGrid", myY2GridMinorEnabled );
309
310   myXGridMaxMajor = resMgr->integerValue( "Plot2d", "HorMajorGridMax", myXGridMaxMajor );
311   myYGridMaxMajor = resMgr->integerValue( "Plot2d", "VerMajorGridMax", myYGridMaxMajor );
312   if ( mySecondY )
313     myY2GridMaxMajor = resMgr->integerValue( "Plot2d", "VerMajorRightGridMax", myY2GridMaxMajor );
314
315   myXGridMaxMinor = resMgr->integerValue( "Plot2d", "HorMinorGridMax", myXGridMaxMinor );
316   myYGridMaxMinor = resMgr->integerValue( "Plot2d", "VerMinorGridMax", myYGridMaxMinor );
317   if ( mySecondY )
318     myY2GridMaxMinor = resMgr->integerValue( "Plot2d", "VerMinorGridMax", myY2GridMaxMinor );
319
320   myXMode = resMgr->integerValue( "Plot2d", "HorScaleMode", myXMode );
321   myXMode = QMAX( 0, QMIN( 1, myXMode ) );
322
323   myYMode = resMgr->integerValue( "Plot2d", "VerScaleMode", myYMode );
324   myYMode = QMAX( 0, QMIN( 1, myYMode ) );
325 }
326
327 /*!
328   Writes Plot2d view settings to the preferences
329 */
330 void Plot2d_ViewFrame::writePreferences()
331 {
332   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
333
334   resMgr->setValue( "Plot2d", "CurveType", myCurveType );
335   resMgr->setValue( "Plot2d", "ShowLegend", myShowLegend );
336   resMgr->setValue( "Plot2d", "LegendPos", myLegendPos );
337   resMgr->setValue( "Plot2d", "MarkerSize", myMarkerSize );
338   resMgr->setValue( "Plot2d", "Background", myBackground );
339   resMgr->setValue( "Plot2d", "ShowTitle", myTitleEnabled );
340   resMgr->setValue( "Plot2d", "ShowHorTitle", myXTitleEnabled );
341   resMgr->setValue( "Plot2d", "ShowVerLeftTitle", myYTitleEnabled );
342   if ( mySecondY )
343     resMgr->setValue( "Plot2d", "ShowVerRightTitle", myY2TitleEnabled );
344
345   resMgr->setValue( "Plot2d", "EnableHorMajorGrid", myXGridMajorEnabled );
346   resMgr->setValue( "Plot2d", "EnableVerMajorGrid", myYGridMajorEnabled );
347   resMgr->setValue( "Plot2d", "EnableHorMinorGrid", myXGridMinorEnabled );
348   resMgr->setValue( "Plot2d", "EnableVerMinorGrid", myYGridMinorEnabled );
349
350   resMgr->setValue( "Plot2d", "HorMajorGridMax", myXGridMaxMajor );
351   resMgr->setValue( "Plot2d", "VerMajorGridMax", myYGridMaxMajor );
352
353   resMgr->setValue( "Plot2d", "HorMinorGridMax", myXGridMaxMinor );
354   resMgr->setValue( "Plot2d", "VerMinorGridMax", myYGridMaxMinor );
355
356   resMgr->setValue( "Plot2d", "HorScaleMode", myXMode );
357
358   if ( mySecondY )
359   {
360     resMgr->setValue( "Plot2d", "EnableRightVerMajorGrid", myY2GridMajorEnabled );
361     resMgr->setValue( "Plot2d", "EnableRightVerMinorGrid", myY2GridMinorEnabled );
362     resMgr->setValue( "Plot2d", "VerRightMajorGridMax", myY2GridMaxMajor );
363     resMgr->setValue( "Plot2d", "VerRightMinorGridMax", myY2GridMaxMinor );
364   }
365
366   resMgr->setValue( "Plot2d", "VerScaleMode", myYMode );
367 }
368
369 /*!
370   Prints mouse cursor coordinates into string
371 */
372 QString Plot2d_ViewFrame::getInfo( const QPoint& pnt ) 
373 {
374   int i;
375   bool xFound = false, yFound = false;
376   double xCoord, yCoord;
377   const QwtScaleDiv* aXscale = myPlot->axisScale( QwtPlot::xBottom );
378   for ( i = 0; i < aXscale->majCnt(); i++ ) {
379     double majXmark = aXscale->majMark( i );
380     int xmark = myPlot->transform( QwtPlot::xBottom, majXmark );
381     if ( xmark-2 == pnt.x() ) {
382       xCoord = majXmark; 
383       xFound = true;
384 //      MESSAGE("Plot2d_ViewFrame::getInfo : close maj X mark("<<i<<") = "<<majXmark<<" "<<xmark<<" "<<pnt.x());
385       break;
386     }
387   }
388   if ( !xFound ) {
389     for ( i = 0; i < aXscale->minCnt(); i++ ) {
390       double minXmark = aXscale->minMark( i );
391       int xmark = myPlot->transform( QwtPlot::xBottom, minXmark );
392       if ( xmark-2 == pnt.x() ) {
393         xCoord = minXmark; 
394         xFound = true;
395 //        MESSAGE("Plot2d_ViewFrame::getInfo : close min X mark("<<i<<") = "<<minXmark<<" "<<xmark<<" "<<pnt.x());
396         break;
397       }
398     }
399   }  
400   const QwtScaleDiv* aYscale = myPlot->axisScale( QwtPlot::yLeft );
401   for ( i = 0; i < aYscale->majCnt(); i++ ) {
402     double majYmark = aYscale->majMark( i );
403     int ymark = myPlot->transform( QwtPlot::yLeft, majYmark );
404     if ( ymark-2 == pnt.y() ) {
405       yCoord = majYmark; 
406       yFound = true;
407       break;
408     }
409   }
410   if ( !yFound ) {
411     for ( i = 0; i < aYscale->minCnt(); i++ ) {
412       double minYmark = aYscale->minMark( i );
413       int ymark = myPlot->transform( QwtPlot::yLeft, minYmark );
414       if ( ymark-2 == pnt.y() ) {
415         yCoord = minYmark; 
416         yFound = true;
417         break;
418       }
419     }
420   }  
421
422   QString strX = QString::number( xFound ? xCoord : myPlot->invTransform( QwtPlot::xBottom, pnt.x() ) ).stripWhiteSpace();
423   if ( strX == "-0" )
424     strX = "0";
425   QString strY = QString::number( yFound ? yCoord : myPlot->invTransform( QwtPlot::yLeft, pnt.y() ) ).stripWhiteSpace();
426   if ( strY == "-0" )
427     strY = "0";
428   QString info = "";
429
430   if (mySecondY) {
431     bool yFound2 = false;
432     double yCoord2;
433
434     const QwtScaleDiv* aYscale2 = myPlot->axisScale( QwtPlot::yRight );
435     for ( i = 0; i < aYscale2->majCnt(); i++ ) {
436       double majYmark = aYscale2->majMark( i );
437       int ymark = myPlot->transform( QwtPlot::yRight, majYmark );
438       if ( ymark-2 == pnt.y() ) {
439         yCoord2 = majYmark; 
440         yFound2 = true;
441         break;
442       }
443     }
444     if ( !yFound2 ) {
445       for ( i = 0; i < aYscale2->minCnt(); i++ ) {
446         double minYmark = aYscale2->minMark( i );
447         int ymark = myPlot->transform( QwtPlot::yRight, minYmark );
448         if ( ymark-2 == pnt.y() ) {
449           yCoord2 = minYmark; 
450           yFound2 = true;
451           break;
452         }
453       }
454     }
455     QString strY2 = QString::number( yFound2 ? yCoord2 : 
456                       myPlot->invTransform( QwtPlot::yRight, pnt.y() ) ).stripWhiteSpace();
457     if ( strY2 == "-0" )
458     strY2 = "0";
459     info = tr("INF_COORDINATES_SOME_Y").arg( strX ).arg( strY ).arg( strY2 );
460   }
461   else
462     info = tr("INF_COORDINATES").arg( strX ).arg( strY );
463
464   return info;
465 }
466
467 /*!
468   Converts Plot2d_Curve's marker style to Qwt marker style [ static ]
469 */
470 static QwtSymbol::Style plot2qwtMarker( Plot2d_Curve::MarkerType m )
471 {
472   QwtSymbol::Style ms = QwtSymbol::None;  
473   switch ( m ) {
474   case Plot2d_Curve::Circle:
475     ms = QwtSymbol::Ellipse;   break;
476   case Plot2d_Curve::Rectangle:
477     ms = QwtSymbol::Rect;      break;
478   case Plot2d_Curve::Diamond:
479     ms = QwtSymbol::Diamond;   break;
480   case Plot2d_Curve::DTriangle:
481     ms = QwtSymbol::DTriangle; break;
482   case Plot2d_Curve::UTriangle:
483     ms = QwtSymbol::UTriangle; break;
484   case Plot2d_Curve::LTriangle: // Qwt confuses LTriangle and RTriangle :(((
485     ms = QwtSymbol::RTriangle; break;
486   case Plot2d_Curve::RTriangle: // Qwt confuses LTriangle and RTriangle :(((
487     ms = QwtSymbol::LTriangle; break;
488   case Plot2d_Curve::Cross:
489     ms = QwtSymbol::Cross;     break;
490   case Plot2d_Curve::XCross:
491     ms = QwtSymbol::XCross;    break;
492   case Plot2d_Curve::None:
493   default:
494     ms = QwtSymbol::None;      break;
495   }
496   return ms;
497 }
498
499 /*!
500   Converts Qwt marker style to Plot2d_Curve's marker style [ static ]
501 */
502 static Plot2d_Curve::MarkerType qwt2plotMarker( QwtSymbol::Style m )
503 {
504   Plot2d_Curve::MarkerType ms = Plot2d_Curve::None;  
505   switch ( m ) {
506   case QwtSymbol::Ellipse:
507     ms = Plot2d_Curve::Circle;    break;
508   case QwtSymbol::Rect:
509     ms = Plot2d_Curve::Rectangle; break;
510   case QwtSymbol::Diamond:
511     ms = Plot2d_Curve::Diamond;   break;
512   case QwtSymbol::DTriangle:
513     ms = Plot2d_Curve::DTriangle; break;
514   case QwtSymbol::UTriangle:
515     ms = Plot2d_Curve::UTriangle; break;
516   case QwtSymbol::RTriangle: // Qwt confuses LTriangle and RTriangle :(((
517     ms = Plot2d_Curve::LTriangle; break;
518   case QwtSymbol::LTriangle: // Qwt confuses LTriangle and RTriangle :(((
519     ms = Plot2d_Curve::RTriangle; break;
520   case QwtSymbol::Cross:
521     ms = Plot2d_Curve::Cross;     break;
522   case QwtSymbol::XCross:
523     ms = Plot2d_Curve::XCross;    break;
524   case QwtSymbol::None:
525   default:
526     ms = Plot2d_Curve::None;      break;
527   }
528   return ms;
529 }
530
531 /*!
532   Converts Plot2d_Curve's line style to Qwt line style [ static ]
533 */
534 static Qt::PenStyle plot2qwtLine( Plot2d_Curve::LineType p )
535 {
536   Qt::PenStyle ps = Qt::NoPen;
537   switch ( p ) {
538   case Plot2d_Curve::Solid:
539     ps = Qt::SolidLine;      break;
540   case Plot2d_Curve::Dash:
541     ps = Qt::DashLine;       break;
542   case Plot2d_Curve::Dot:
543     ps = Qt::DotLine;        break;
544   case Plot2d_Curve::DashDot:
545     ps = Qt::DashDotLine;    break;
546   case Plot2d_Curve::DashDotDot:
547     ps = Qt::DashDotDotLine; break;
548   case Plot2d_Curve::NoPen:
549   default:
550     ps = Qt::NoPen;          break;
551   }
552   return ps;
553 }
554
555 /*!
556   Converts Qwt line style to Plot2d_Curve's line style [ static ]
557 */
558 static Plot2d_Curve::LineType qwt2plotLine( Qt::PenStyle p )
559 {
560   Plot2d_Curve::LineType ps = Plot2d_Curve::NoPen;
561   switch ( p ) {
562   case Qt::SolidLine:
563     ps = Plot2d_Curve::Solid;      break;
564   case Qt::DashLine:
565     ps = Plot2d_Curve::Dash;       break;
566   case Qt::DotLine:
567     ps = Plot2d_Curve::Dot;        break;
568   case Qt::DashDotLine:
569     ps = Plot2d_Curve::DashDot;    break;
570   case Qt::DashDotDotLine:
571     ps = Plot2d_Curve::DashDotDot; break;
572   case Qt::NoPen:
573   default:
574     ps = Plot2d_Curve::NoPen;      break;
575   }
576   return ps;
577 }
578
579 /*!
580   Adds curve into view
581 */
582 void Plot2d_ViewFrame::displayCurve( Plot2d_Curve* curve, bool update )
583 {
584   if ( !curve )
585     return;
586   if ( hasCurve( curve ) ) {
587     updateCurve( curve, update );
588   }
589   else {
590     long curveKey = myPlot->insertCurve( curve->getVerTitle() );
591     myPlot->setCurveYAxis(curveKey, curve->getYAxis());
592
593     myCurves.insert( curveKey, curve );
594     if ( curve->isAutoAssign() ) {
595       QwtSymbol::Style typeMarker;
596       QColor           color;
597       Qt::PenStyle     typeLine;
598       myPlot->getNextMarker( typeMarker, color, typeLine );
599       myPlot->setCurvePen( curveKey, QPen( color, DEFAULT_LINE_WIDTH, typeLine ) );
600       myPlot->setCurveSymbol( curveKey, QwtSymbol( typeMarker, 
601                QBrush( color ), 
602                QPen( color ), 
603                QSize( myMarkerSize, myMarkerSize ) ) );
604       curve->setColor( color );
605       curve->setLine( qwt2plotLine( typeLine ) );
606       curve->setMarker( qwt2plotMarker( typeMarker ) );
607     }
608     else {
609       Qt::PenStyle     ps = plot2qwtLine( curve->getLine() );
610       QwtSymbol::Style ms = plot2qwtMarker( curve->getMarker() );
611       myPlot->setCurvePen( curveKey, QPen( curve->getColor(), curve->getLineWidth(), ps ) );
612       myPlot->setCurveSymbol( curveKey, QwtSymbol( ms, 
613                QBrush( curve->getColor() ), 
614                QPen( curve->getColor() ), 
615                QSize( myMarkerSize, myMarkerSize ) ) );
616     }
617     if ( myCurveType == 0 )
618       myPlot->setCurveStyle( curveKey, QwtCurve::NoCurve );
619     else if ( myCurveType == 1 )
620       myPlot->setCurveStyle( curveKey, QwtCurve::Lines );
621     else if ( myCurveType == 2 )
622       myPlot->setCurveStyle( curveKey, QwtCurve::Spline );
623     myPlot->setCurveData( curveKey, curve->horData(), curve->verData(), curve->nbPoints() );
624   }
625   if ( update )
626     myPlot->replot();
627 }
628
629 /*!
630   Adds curves into view
631 */
632 void Plot2d_ViewFrame::displayCurves( curveList curves, bool update )
633 {
634   myPlot->setUpdatesEnabled( false );
635   QPtrListIterator<Plot2d_Curve> it(curves);
636   Plot2d_Curve* aCurve;
637   while( (aCurve = it.current()) ) {
638     displayCurve( aCurve, false );
639     ++it;
640   }
641
642   fitAll();
643   myPlot->setUpdatesEnabled( true );
644   if ( update )
645     myPlot->replot();
646 }
647
648 /*!
649   Erases curve
650 */
651 void Plot2d_ViewFrame::eraseCurve( Plot2d_Curve* curve, bool update )
652 {
653   if ( !curve )
654     return;
655   int curveKey = hasCurve( curve );
656   if ( curveKey ) {
657     myPlot->removeCurve( curveKey );
658     myCurves.remove( curveKey );
659     if ( update )
660       myPlot->replot();
661   }
662 }
663
664 /*!
665   Erases curves
666 */
667 void Plot2d_ViewFrame::eraseCurves( curveList& curves, bool update )
668 {
669   QPtrListIterator<Plot2d_Curve> it(curves);
670   Plot2d_Curve* aCurve;
671   while( (aCurve = it.current()) ) {
672     eraseCurve( aCurve, false );
673     ++it;
674   }
675 //  fitAll();
676   if ( update )
677     myPlot->replot();
678 }
679
680 /*!
681   Updates curves attributes
682 */
683 void Plot2d_ViewFrame::updateCurve( Plot2d_Curve* curve, bool update )
684 {
685   if ( !curve )
686     return;
687   int curveKey = hasCurve( curve );
688   if ( curveKey ) {
689     if ( !curve->isAutoAssign() ) {
690       Qt::PenStyle     ps = plot2qwtLine( curve->getLine() );
691       QwtSymbol::Style ms = plot2qwtMarker( curve->getMarker() );
692       myPlot->setCurvePen( curveKey, QPen( curve->getColor(), curve->getLineWidth(), ps ) );
693       myPlot->setCurveSymbol( curveKey, QwtSymbol( ms, 
694                QBrush( curve->getColor() ), 
695                QPen( curve->getColor() ), 
696                QSize( myMarkerSize, myMarkerSize ) ) );
697       myPlot->setCurveData( curveKey, curve->horData(), curve->verData(), curve->nbPoints() );
698     }
699     myPlot->setCurveTitle( curveKey, curve->getVerTitle() );
700     myPlot->curve( curveKey )->setEnabled( true );
701     if ( update )
702       myPlot->replot();
703   }
704 }
705
706 /*!
707   Returns curve key if is is displayed in the viewer and 0 otherwise
708 */
709 int Plot2d_ViewFrame::hasCurve( Plot2d_Curve* curve )
710 {
711   QIntDictIterator<Plot2d_Curve> it( myCurves );
712   for ( ; it.current(); ++it ) {
713     if ( it.current() == curve )
714       return it.currentKey();
715   }
716   return 0;
717 }
718
719 /*!
720   Gets lsit of displayed curves
721 */
722 int Plot2d_ViewFrame::getCurves( QList<Plot2d_Curve>& clist )
723 {
724   clist.clear();
725   clist.setAutoDelete( false );
726   QIntDictIterator<Plot2d_Curve> it( myCurves );
727   for ( ; it.current(); ++it ) {
728     clist.append( it.current() );
729   }
730   return clist.count();
731 }
732
733 /*!
734   Returns true if the curve is visible
735 */
736 bool Plot2d_ViewFrame::isVisible( Plot2d_Curve* curve )
737 {
738   if(curve) {
739     int key = hasCurve( curve );
740     if ( key )
741       return myPlot->curve( key )->enabled();
742   }
743   return false;
744
745
746 /*!
747   update legend
748 */
749 void Plot2d_ViewFrame::updateLegend( const Plot2d_Prs* prs )
750 {
751   if ( !prs || prs->IsNull() )
752     return;
753   curveList aCurves = prs->getCurves();
754
755   QPtrListIterator<Plot2d_Curve> it(aCurves);
756   Plot2d_Curve* aCurve;
757   while( (aCurve = it.current()) ) {
758     int curveKey = hasCurve( aCurve );
759     if ( curveKey )
760       myPlot->setCurveTitle( curveKey, aCurve->getVerTitle() );
761     ++it;
762   }
763 }
764
765 /*!
766   Fits the view to see all data
767 */
768 void Plot2d_ViewFrame::fitAll()
769 {
770   QwtDiMap xMap1 = myPlot->canvasMap( QwtPlot::xBottom );
771
772   myPlot->setAxisAutoScale( QwtPlot::yLeft );
773   myPlot->setAxisAutoScale( QwtPlot::xBottom );
774   myPlot->replot();
775
776   // for existing grid
777   QwtDiMap xMap = myPlot->canvasMap( QwtPlot::xBottom );
778   QwtDiMap yMap = myPlot->canvasMap( QwtPlot::yLeft );
779
780   myPlot->setAxisScale( QwtPlot::xBottom, 
781       myPlot->invTransform( QwtPlot::xBottom, xMap.i1() ), 
782       myPlot->invTransform( QwtPlot::xBottom, xMap.i2() ) );
783   myPlot->setAxisScale( QwtPlot::yLeft, 
784       myPlot->invTransform( QwtPlot::yLeft, yMap.i1() ), 
785       myPlot->invTransform( QwtPlot::yLeft, yMap.i2() ) );
786
787   if (mySecondY) {
788     myPlot->setAxisAutoScale( QwtPlot::yRight );
789     myPlot->replot();
790     QwtDiMap yMap2 = myPlot->canvasMap( QwtPlot::yRight );
791     myPlot->setAxisScale( QwtPlot::yRight, 
792         myPlot->invTransform( QwtPlot::yRight, yMap2.i1() ), 
793         myPlot->invTransform( QwtPlot::yRight, yMap2.i2() ) );
794   }
795   myPlot->replot();
796 }
797
798 /*!
799   Fits the view to rectangle area (pixels)
800 */
801 void Plot2d_ViewFrame::fitArea( const QRect& area )
802 {
803   QRect rect = area.normalize();
804   if ( rect.width() < MIN_RECT_SIZE ) {
805     rect.setWidth( MIN_RECT_SIZE );
806     rect.setLeft( rect.left() - MIN_RECT_SIZE/2 );
807   }
808   if ( rect.height() < MIN_RECT_SIZE ) {
809     rect.setHeight( MIN_RECT_SIZE );
810     rect.setTop( rect.top() - MIN_RECT_SIZE/2 );
811   }
812   myPlot->setAxisScale( QwtPlot::yLeft, 
813             myPlot->invTransform( QwtPlot::yLeft, rect.top() ), 
814             myPlot->invTransform( QwtPlot::yLeft, rect.bottom() ) );
815   if (mySecondY)
816     myPlot->setAxisScale( QwtPlot::yRight, 
817             myPlot->invTransform( QwtPlot::yRight, rect.top() ), 
818             myPlot->invTransform( QwtPlot::yRight, rect.bottom() ) );
819   myPlot->setAxisScale( QwtPlot::xBottom, 
820             myPlot->invTransform( QwtPlot::xBottom, rect.left() ), 
821             myPlot->invTransform( QwtPlot::xBottom, rect.right() ) );
822   myPlot->replot();
823 }
824
825 /*!
826   Tests if it is necessary to start operation on mouse action
827 */
828 int Plot2d_ViewFrame::testOperation( const QMouseEvent& me )
829 {
830   int btn = me.button() | me.state();
831   const int zoomBtn = ControlButton | LeftButton;
832   const int panBtn  = ControlButton | MidButton;
833   const int fitBtn  = ControlButton | RightButton;
834
835   switch (btn)
836   {
837   case zoomBtn:
838     myPlot->canvas()->setCursor( zoomCursor );
839     return ZoomId;
840   case panBtn:
841     myPlot->canvas()->setCursor( QCursor( Qt::SizeAllCursor ) );
842     return PanId;
843   case fitBtn:
844     myPlot->canvas()->setCursor( QCursor( Qt::PointingHandCursor ) );
845     return FitAreaId;
846   default :
847     return NoOpId;
848   }
849 }
850
851 /*!
852   "Settings" toolbar action slot
853 */
854 void Plot2d_ViewFrame::onSettings()
855 {
856 #ifdef TEST_AUTOASSIGN
857   typedef QMap<int,int> IList;
858   typedef QMap<QString,int> SList;
859   IList mars, lins;
860   SList cols;
861   cols[ "red-min" ]   = 1000;
862   cols[ "red-max" ]   = -1;
863   cols[ "green-min" ] = 1000;
864   cols[ "green-max" ] = -1;
865   cols[ "blue-min" ]  = 1000;
866   cols[ "blue-max" ]  = -1;
867   for ( unsigned i = 0; i < 10000; i++ ) {
868     QwtSymbol::Style typeMarker;
869     QColor           color;
870     Qt::PenStyle     typeLine;
871     myPlot->getNextMarker( typeMarker, color, typeLine );
872     if ( mars.contains(typeMarker) )
873       mars[ typeMarker ] = mars[ typeMarker ]+1;
874     else
875       mars[ typeMarker ] = 0;
876     if ( lins.contains(typeLine) )
877       lins[ typeLine ] = lins[ typeLine ]+1;
878     else
879       lins[ typeLine ] = 0;
880     if ( cols[ "red-max" ] < color.red() )
881       cols[ "red-max" ] = color.red();
882     if ( cols[ "red-min" ] > color.red() )
883       cols[ "red-min" ] = color.red();
884     if ( cols[ "green-max" ] < color.green() )
885       cols[ "green-max" ] = color.green();
886     if ( cols[ "green-min" ] > color.green() )
887       cols[ "green-min" ] = color.green();
888     if ( cols[ "blue-max" ] < color.blue() )
889       cols[ "blue-max" ] = color.blue();
890     if ( cols[ "blue-min" ] > color.blue() )
891       cols[ "blue-min" ] = color.blue();
892   }
893   for (IList::Iterator it = mars.begin();  it != mars.end(); ++it)
894     MESSAGE("markers( " << it.key() << ") = " << it.data() );
895   for (IList::Iterator it = lins.begin();  it != lins.end(); ++it)
896     MESSAGE("lines( " << it.key() << ") = " << it.data() );
897   for (SList::Iterator it = cols.begin();  it != cols.end(); ++it)
898     MESSAGE("colors( " << it.key() << ") = " << it.data() );
899 #endif
900   
901   Plot2d_SetupViewDlg* dlg = new Plot2d_SetupViewDlg( this, true, mySecondY );
902   dlg->setMainTitle( myTitleEnabled, myTitle );
903   dlg->setXTitle( myXTitleEnabled, myXTitle );
904   dlg->setYTitle( myYTitleEnabled, myYTitle );
905   if (mySecondY)
906     dlg->setY2Title( myY2TitleEnabled, myY2Title );
907   dlg->setCurveType( myCurveType );
908   dlg->setLegend( myShowLegend, myLegendPos );
909   dlg->setMarkerSize( myMarkerSize );
910   dlg->setBackgroundColor( myBackground );
911   dlg->setScaleMode(myXMode, myYMode);
912   //
913   dlg->setMajorGrid( myXGridMajorEnabled, myPlot->axisMaxMajor( QwtPlot::xBottom ),
914          myYGridMajorEnabled, myPlot->axisMaxMajor( QwtPlot::yLeft ),
915          myY2GridMajorEnabled, myPlot->axisMaxMajor( QwtPlot::yRight ) );
916   dlg->setMinorGrid( myXGridMinorEnabled, myPlot->axisMaxMinor( QwtPlot::xBottom ),
917          myYGridMinorEnabled, myPlot->axisMaxMinor( QwtPlot::yLeft ),
918          myY2GridMinorEnabled, myPlot->axisMaxMinor( QwtPlot::yRight ) );
919   if ( dlg->exec() == QDialog::Accepted ) {
920     // horizontal axis title
921     setTitle( dlg->isXTitleEnabled(), dlg->getXTitle(), XTitle, false );
922     // vertical left axis title
923     setTitle( dlg->isYTitleEnabled(), dlg->getYTitle(), YTitle, false );
924     if (mySecondY) // vertical right axis title
925       setTitle( dlg->isY2TitleEnabled(), dlg->getY2Title(), Y2Title, false );
926
927     // main title
928     setTitle( dlg->isMainTitleEnabled(), dlg->getMainTitle(), MainTitle, true );
929     // curve type
930     if ( myCurveType != dlg->getCurveType() ) {
931       setCurveType( dlg->getCurveType(), false );
932     }
933     // legend
934     if ( myShowLegend != dlg->isLegendEnabled() ) {
935       showLegend( dlg->isLegendEnabled(), false );
936     }
937     if ( myLegendPos != dlg->getLegendPos() ) {
938       setLegendPos( dlg->getLegendPos() );
939     }
940     // marker size
941     if ( myMarkerSize != dlg->getMarkerSize() ) {
942       setMarkerSize( dlg->getMarkerSize(), false );
943     }
944     // background color
945     if ( myBackground != dlg->getBackgroundColor() ) {
946       setBackgroundColor( dlg->getBackgroundColor() );
947     }
948     // grid
949     bool aXGridMajorEnabled, aXGridMinorEnabled, aYGridMajorEnabled, aYGridMinorEnabled,
950          aY2GridMajorEnabled, aY2GridMinorEnabled;
951     int  aXGridMaxMajor, aXGridMaxMinor, aYGridMaxMajor, aYGridMaxMinor,
952          aY2GridMaxMajor, aY2GridMaxMinor;
953     dlg->getMajorGrid( aXGridMajorEnabled, aXGridMaxMajor, aYGridMajorEnabled, aYGridMaxMajor,
954                        aY2GridMajorEnabled, aY2GridMaxMajor);
955     dlg->getMinorGrid( aXGridMinorEnabled, aXGridMaxMinor, aYGridMinorEnabled, aYGridMaxMinor,
956                        aY2GridMinorEnabled, aY2GridMaxMinor);
957     setXGrid( aXGridMajorEnabled, aXGridMaxMajor, aXGridMinorEnabled, aXGridMaxMinor, false );
958     setYGrid( aYGridMajorEnabled, aYGridMaxMajor, aYGridMinorEnabled, aYGridMaxMinor,
959               aY2GridMajorEnabled, aY2GridMaxMajor, aY2GridMinorEnabled, aY2GridMaxMinor, false );
960     if ( myXMode != dlg->getXScaleMode() ) {
961       setHorScaleMode( dlg->getXScaleMode() );
962     }
963     if ( myYMode != dlg->getYScaleMode() ) {
964       setVerScaleMode( dlg->getYScaleMode() );
965     }
966     // update view
967     myPlot->replot();
968     // update preferences
969     if ( dlg->isSetAsDefault() ) 
970       writePreferences();
971   }
972   delete dlg;
973 }
974
975 /*!
976   "Fit Data" command slot
977 */
978 void Plot2d_ViewFrame::onFitData()
979 {
980   Plot2d_FitDataDlg* dlg = new Plot2d_FitDataDlg( this, mySecondY );
981   int ixMin = myPlot->canvasMap( QwtPlot::xBottom ).i1();
982   int ixMax = myPlot->canvasMap( QwtPlot::xBottom ).i2();
983   int iyMin = myPlot->canvasMap( QwtPlot::yLeft ).i1();
984   int iyMax = myPlot->canvasMap( QwtPlot::yLeft ).i2();
985   double xMin = myPlot->invTransform(QwtPlot::xBottom, ixMin);
986   double xMax = myPlot->invTransform(QwtPlot::xBottom, ixMax);
987   double yMin = myPlot->invTransform(QwtPlot::yLeft, iyMin);
988   double yMax = myPlot->invTransform(QwtPlot::yLeft, iyMax);
989   double y2Min = 0;
990   double y2Max = 0;
991   if (mySecondY) {
992     int iyMin = myPlot->canvasMap( QwtPlot::yRight ).i1();
993     int iyMax = myPlot->canvasMap( QwtPlot::yRight ).i2();
994     y2Min = myPlot->invTransform(QwtPlot::yRight, iyMin);
995     y2Max = myPlot->invTransform(QwtPlot::yRight, iyMax);
996   }
997   
998   dlg->setRange( xMin, xMax, yMin, yMax, y2Min, y2Max );
999   if ( dlg->exec() == QDialog::Accepted ) {
1000     int mode = dlg->getRange( xMin, xMax, yMin, yMax, y2Min, y2Max );
1001     if ( mode == 0 || mode == 2 ) {
1002       myPlot->setAxisScale( QwtPlot::yLeft, yMax, yMin );
1003       if (mySecondY)
1004         myPlot->setAxisScale( QwtPlot::yRight, y2Max, y2Min );
1005     }
1006     if ( mode == 0 || mode == 1 ) 
1007       myPlot->setAxisScale( QwtPlot::xBottom, xMin, xMax ); 
1008     myPlot->replot();
1009   }
1010   delete dlg;
1011 }
1012
1013 /*!
1014   Change background color
1015 */
1016 void Plot2d_ViewFrame::onChangeBackground()
1017 {
1018   QColor selColor = QColorDialog::getColor ( backgroundColor(), this ); 
1019   if ( selColor.isValid() ) {
1020     setBackgroundColor( selColor );
1021   }
1022 }
1023
1024 /*!
1025   Sets curve type
1026 */
1027 void Plot2d_ViewFrame::setCurveType( int curveType, bool update )
1028 {
1029   myCurveType = curveType;
1030   QArray<long> keys = myPlot->curveKeys();
1031   for ( int i = 0; i < (int)keys.count(); i++ ) {
1032     if ( myCurveType == 0 )
1033       myPlot->setCurveStyle( keys[i], QwtCurve::Dots );//QwtCurve::NoCurve
1034     else if ( myCurveType == 1 )
1035       myPlot->setCurveStyle( keys[i], QwtCurve::Lines );
1036     else if ( myCurveType == 2 )
1037       myPlot->setCurveStyle( keys[i], QwtCurve::Spline );
1038   }
1039   if ( update )
1040     myPlot->replot();
1041   emit vpCurveChanged();
1042 }
1043
1044 void Plot2d_ViewFrame::setCurveTitle( int curveKey, const QString& title ) 
1045
1046   if(myPlot) myPlot->setCurveTitle(curveKey, title); 
1047 }   
1048
1049 /*!
1050   Shows/hides legend
1051 */
1052 void Plot2d_ViewFrame::showLegend( bool show, bool update )
1053 {
1054   myShowLegend = show;
1055   myPlot->setAutoLegend( myShowLegend );
1056   myPlot->enableLegend( myShowLegend );
1057   if ( update )
1058     myPlot->replot();
1059 }
1060
1061 /*!
1062   Sets legend position : 0 - left, 1 - right, 2 - top, 3 - bottom
1063 */
1064 void Plot2d_ViewFrame::setLegendPos( int pos )
1065 {
1066   myLegendPos = pos;
1067   switch( pos ) {
1068   case 0:
1069     myPlot->setLegendPos( Qwt::Left );
1070     break;
1071   case 1:
1072     myPlot->setLegendPos( Qwt::Right );
1073     break;
1074   case 2:
1075     myPlot->setLegendPos( Qwt::Top );
1076     break;
1077   case 3:
1078     myPlot->setLegendPos( Qwt::Bottom );
1079     break;
1080   }
1081 }
1082
1083 /*!
1084   Sets new marker size
1085 */
1086 void Plot2d_ViewFrame::setMarkerSize( const int size, bool update )
1087 {
1088   if ( myMarkerSize != size )
1089   {
1090     myMarkerSize = size;
1091     QArray<long> keys = myPlot->curveKeys();
1092     for ( int i = 0; i < (int)keys.count(); i++ )
1093     {
1094       QwtPlotCurve* crv = myPlot->curve( keys[i] );
1095       if ( crv )
1096       {
1097         QwtSymbol aSymbol = crv->symbol();
1098         aSymbol.setSize( myMarkerSize, myMarkerSize );
1099         myPlot->setCurveSymbol( keys[i], aSymbol );
1100       }
1101     }
1102     if ( update )
1103       myPlot->replot();
1104   }
1105 }
1106
1107 /*!
1108   Sets background color
1109 */
1110 void Plot2d_ViewFrame::setBackgroundColor( const QColor& color )
1111 {
1112   myBackground = color;
1113   //myPlot->setCanvasBackground( myBackground );
1114   myPlot->canvas()->setPalette( myBackground );
1115   myPlot->setPalette( myBackground );
1116   QPalette aPal = myPlot->getLegend()->palette();
1117   for ( int i = 0; i < QPalette::NColorGroups; i++ ) {
1118     QPalette::ColorGroup cg = (QPalette::ColorGroup)i;
1119     aPal.setColor( cg, QColorGroup::Base, myBackground );
1120     aPal.setColor( cg, QColorGroup::Background, myBackground );
1121   }
1122   myPlot->getLegend()->setPalette( aPal );
1123   Repaint();
1124 }
1125 /*!
1126   Gets background color
1127 */
1128 QColor Plot2d_ViewFrame::backgroundColor() const
1129 {
1130   return myBackground;
1131 }
1132 /*!
1133   Sets hor.axis grid parameters
1134 */
1135 void Plot2d_ViewFrame::setXGrid( bool xMajorEnabled, const int xMajorMax, 
1136          bool xMinorEnabled, const int xMinorMax, 
1137          bool update )
1138 {
1139   myXGridMajorEnabled = xMajorEnabled;
1140   myXGridMinorEnabled = xMinorEnabled;
1141   myXGridMaxMajor = xMajorMax;
1142   myXGridMaxMinor = xMinorMax;
1143   myPlot->setAxisMaxMajor( QwtPlot::xBottom, myXGridMaxMajor );
1144   myPlot->setAxisMaxMinor( QwtPlot::xBottom, myXGridMaxMinor );
1145   myPlot->setGridXAxis(QwtPlot::xBottom);
1146   myPlot->enableGridX( myXGridMajorEnabled );
1147   myPlot->enableGridXMin( myXGridMinorEnabled );
1148   if ( update )
1149     myPlot->replot();
1150 }
1151 /*!
1152   Sets ver.axis grid parameters
1153 */
1154 void Plot2d_ViewFrame::setYGrid( bool yMajorEnabled, const int yMajorMax, 
1155                                  bool yMinorEnabled, const int yMinorMax,
1156                                  bool y2MajorEnabled, const int y2MajorMax, 
1157                                  bool y2MinorEnabled, const int y2MinorMax, 
1158                                  bool update )
1159 {
1160   myYGridMajorEnabled = yMajorEnabled;
1161   myYGridMinorEnabled = yMinorEnabled;
1162   myYGridMaxMajor = yMajorMax;
1163   myYGridMaxMinor = yMinorMax;
1164
1165   if (mySecondY) {
1166     myY2GridMajorEnabled = y2MajorEnabled;
1167     myY2GridMinorEnabled = y2MinorEnabled;
1168     myY2GridMaxMajor = y2MajorMax;
1169     myY2GridMaxMinor = y2MinorMax;
1170   }
1171   myPlot->setAxisMaxMajor( QwtPlot::yLeft, myYGridMaxMajor );
1172   myPlot->setAxisMaxMinor( QwtPlot::yLeft, myYGridMaxMinor );
1173
1174   if (mySecondY) {
1175     myPlot->setAxisMaxMajor( QwtPlot::yRight, myY2GridMaxMajor );
1176     myPlot->setAxisMaxMinor( QwtPlot::yRight, myY2GridMaxMinor );
1177   }
1178
1179   myPlot->setGridYAxis(QwtPlot::yLeft);
1180
1181   if (mySecondY) {
1182     if (myYGridMajorEnabled) {
1183       myPlot->enableGridYMin(myYGridMinorEnabled);
1184       myPlot->enableGridY( myYGridMajorEnabled);
1185     }
1186     else if (myY2GridMajorEnabled) {
1187       myPlot->setGridYAxis(QwtPlot::yRight);
1188       myPlot->enableGridYMin(myY2GridMinorEnabled);
1189       myPlot->enableGridY(myY2GridMajorEnabled);
1190     }
1191     else {
1192       myPlot->enableGridYMin(false);
1193       myPlot->enableGridY(false);
1194     }
1195   }
1196   else {
1197     myPlot->enableGridY( myYGridMajorEnabled );
1198     myPlot->enableGridYMin( myYGridMinorEnabled );
1199   }
1200   if ( update )
1201     myPlot->replot();
1202 }
1203
1204 /*!
1205   Sets title for some axis
1206 */
1207 void Plot2d_ViewFrame::setTitle( bool enabled, const QString& title,
1208                                  ObjectType type, bool update )
1209 {
1210   switch (type) {
1211     case MainTitle:
1212       myTitleEnabled = enabled;
1213       myTitle = title;
1214       myPlot->setTitle( myTitleEnabled ? myTitle : QString::null );
1215       break;
1216     case XTitle:
1217       myXTitleEnabled = enabled;
1218       myXTitle = title;
1219       myPlot->setAxisTitle( QwtPlot::xBottom, myXTitleEnabled ? myXTitle : QString::null );
1220       break;
1221     case YTitle:
1222       myYTitleEnabled = enabled;
1223       myYTitle = title;
1224       myPlot->setAxisTitle( QwtPlot::yLeft, myYTitleEnabled ? myYTitle : QString::null );
1225       break;
1226     case Y2Title:
1227       myY2TitleEnabled = enabled;
1228       myY2Title = title;
1229       myPlot->setAxisTitle( QwtPlot::yRight, myY2TitleEnabled ? myY2Title : QString::null );
1230       break;
1231   }
1232   if ( update )
1233     myPlot->replot();
1234 }
1235 /*!
1236   Sets title for some axis
1237 */
1238 QString Plot2d_ViewFrame::getTitle( ObjectType type ) const
1239 {
1240   QString title = "";
1241   switch (type) {
1242     case MainTitle:
1243       title = myTitle;   break;
1244     case XTitle:
1245       title = myXTitle;  break;
1246     case YTitle:
1247       title = myYTitle;  break;
1248     case Y2Title:
1249       title = myY2Title; break;
1250   }
1251   return title;
1252 }
1253 /*!
1254   Sets font for Plot2d object : title or axis
1255 */
1256 void Plot2d_ViewFrame::setFont( const QFont& font, ObjectType type, bool update)
1257 {
1258   switch (type) {
1259     case MainTitle:
1260       myPlot->setTitleFont(font);
1261       break;
1262     case XTitle:
1263       myPlot->setAxisTitleFont(QwtPlot::xBottom, font); break;
1264     case YTitle:
1265       myPlot->setAxisTitleFont(QwtPlot::yLeft, font);   break;
1266     case Y2Title:
1267       myPlot->setAxisTitleFont(QwtPlot::yRight, font);  break;
1268     case XAxis:
1269       myPlot->setAxisFont(QwtPlot::xBottom, font);      break;
1270     case YAxis:
1271       myPlot->setAxisFont(QwtPlot::yLeft, font);        break;
1272     case Y2Axis:
1273       myPlot->setAxisFont(QwtPlot::yRight, font);       break;
1274   }
1275   if ( update )
1276     myPlot->replot();
1277 }
1278 /*!
1279   Sets scale mode for horizontal axis: 0 - linear, 1 - logarithmic
1280 */
1281 void Plot2d_ViewFrame::setHorScaleMode( const int mode, bool update )
1282 {
1283   myXMode = mode;
1284   if ( myXMode == 0 ) // linear
1285     myPlot->changeAxisOptions( QwtPlot::xBottom, QwtAutoScale::Logarithmic, false );
1286   else                // logarithmic
1287     myPlot->changeAxisOptions( QwtPlot::xBottom, QwtAutoScale::Logarithmic, true );
1288
1289   if ( update )
1290     fitAll();
1291   emit vpModeHorChanged();
1292 }
1293 /*!
1294   Sets scale mode for vertical axis: 0 - linear, 1 - logarithmic
1295 */
1296 void Plot2d_ViewFrame::setVerScaleMode( const int mode, bool update )
1297 {
1298   myYMode = mode;
1299   if ( myYMode == 0 ) { // linear
1300     myPlot->changeAxisOptions( QwtPlot::yLeft, QwtAutoScale::Logarithmic, false );
1301     if (mySecondY)
1302       myPlot->changeAxisOptions( QwtPlot::yRight, QwtAutoScale::Logarithmic, false );
1303   }
1304   else {               // logarithmic
1305     myPlot->changeAxisOptions( QwtPlot::yLeft, QwtAutoScale::Logarithmic, true );
1306     if (mySecondY)
1307       myPlot->changeAxisOptions( QwtPlot::yRight, QwtAutoScale::Logarithmic, true );
1308   }
1309   if ( update )
1310     fitAll();
1311   emit vpModeVerChanged();
1312 }
1313
1314 /*!
1315   Return, scale mode for horizontal axis
1316 */
1317 bool Plot2d_ViewFrame::isModeHorLinear()
1318 {
1319   return (myXMode == 0 ? true : false);
1320 }
1321
1322 /*!
1323   Return, scale mode for vertical axis
1324 */
1325 bool Plot2d_ViewFrame::isModeVerLinear()
1326 {
1327   return (myYMode == 0 ? true : false);
1328 }
1329 /*!
1330   Slot, called when user presses mouse button
1331 */
1332 void Plot2d_ViewFrame::plotMousePressed(const QMouseEvent& me )
1333 {
1334   if ( myOperation == NoOpId )
1335     myOperation = testOperation( me );
1336   if ( myOperation != NoOpId ) {
1337     myPnt = me.pos();
1338     if ( myOperation == FitAreaId ) {
1339       myPlot->setOutlineStyle( Qwt::Rect );
1340     }
1341     else if ( myOperation == GlPanId ) {
1342       myPlot->setAxisScale( QwtPlot::yLeft,
1343           myPlot->invTransform( QwtPlot::yLeft, myPnt.y() ) + myYDistance/2, 
1344           myPlot->invTransform( QwtPlot::yLeft, myPnt.y() ) - myYDistance/2 );
1345       myPlot->setAxisScale( QwtPlot::xBottom, 
1346           myPlot->invTransform( QwtPlot::xBottom, myPnt.x() ) - myXDistance/2, 
1347           myPlot->invTransform( QwtPlot::xBottom, myPnt.x() ) + myXDistance/2 );
1348       if (mySecondY)
1349         myPlot->setAxisScale( QwtPlot::yRight,
1350           myPlot->invTransform( QwtPlot::yRight, myPnt.y() ) + myYDistance2/2, 
1351           myPlot->invTransform( QwtPlot::yRight, myPnt.y() ) - myYDistance2/2 );
1352       myPlot->replot();
1353     }
1354   }
1355   else {
1356     int btn = me.button() | me.state();
1357     if (btn == RightButton) {
1358       QMouseEvent* aEvent = new QMouseEvent(QEvent::MouseButtonPress,
1359                                             me.pos(), btn, me.state());
1360       // QMouseEvent 'me' has the 'MouseButtonDblClick' type. In this case we create new event 'aEvent'.
1361       parent()->eventFilter(this, aEvent);
1362     }
1363   }
1364 }
1365 /*!
1366   Slot, called when user moves mouse
1367 */
1368 void Plot2d_ViewFrame::plotMouseMoved( const QMouseEvent& me )
1369 {
1370   int    dx = me.pos().x() - myPnt.x();
1371   int    dy = me.pos().y() - myPnt.y();
1372
1373   if ( myOperation != NoOpId) {
1374     if ( myOperation == ZoomId ) {
1375       QwtDiMap xMap = myPlot->canvasMap( QwtPlot::xBottom );
1376       QwtDiMap yMap = myPlot->canvasMap( QwtPlot::yLeft );
1377
1378       myPlot->setAxisScale( QwtPlot::yLeft, 
1379           myPlot->invTransform( QwtPlot::yLeft, yMap.i1() ), 
1380           myPlot->invTransform( QwtPlot::yLeft, yMap.i2() + dy ) );
1381       myPlot->setAxisScale( QwtPlot::xBottom, 
1382           myPlot->invTransform( QwtPlot::xBottom, xMap.i1() ), 
1383           myPlot->invTransform( QwtPlot::xBottom, xMap.i2() - dx ) );
1384       if (mySecondY) {
1385         QwtDiMap y2Map = myPlot->canvasMap( QwtPlot::yRight );
1386         myPlot->setAxisScale( QwtPlot::yRight, 
1387           myPlot->invTransform( QwtPlot::yRight, y2Map.i1() ), 
1388           myPlot->invTransform( QwtPlot::yRight, y2Map.i2() + dy ) );
1389       }
1390       myPlot->replot();
1391       myPnt = me.pos();
1392     }
1393     else if ( myOperation == PanId ) {
1394       QwtDiMap xMap = myPlot->canvasMap( QwtPlot::xBottom );
1395       QwtDiMap yMap = myPlot->canvasMap( QwtPlot::yLeft );
1396
1397       myPlot->setAxisScale( QwtPlot::yLeft, 
1398           myPlot->invTransform( QwtPlot::yLeft, yMap.i1()-dy ), 
1399           myPlot->invTransform( QwtPlot::yLeft, yMap.i2()-dy ) );
1400       myPlot->setAxisScale( QwtPlot::xBottom, 
1401           myPlot->invTransform( QwtPlot::xBottom, xMap.i1()-dx ),
1402           myPlot->invTransform( QwtPlot::xBottom, xMap.i2()-dx ) ); 
1403       if (mySecondY) {
1404         QwtDiMap y2Map = myPlot->canvasMap( QwtPlot::yRight );
1405         myPlot->setAxisScale( QwtPlot::yRight,
1406           myPlot->invTransform( QwtPlot::yRight, y2Map.i1()-dy ), 
1407           myPlot->invTransform( QwtPlot::yRight, y2Map.i2()-dy ) );
1408       }
1409       myPlot->replot();
1410       myPnt = me.pos();
1411     }
1412   }
1413   else {
1414     ((Plot2d_ViewWindow*)parent())->putInfo(getInfo(me.pos()));
1415   }
1416 }
1417 /*!
1418   Slot, called when user releases mouse
1419 */
1420 void Plot2d_ViewFrame::plotMouseReleased( const QMouseEvent& me )
1421 {
1422   if ( myOperation == NoOpId && me.button() == RightButton )
1423   {
1424     QContextMenuEvent aEvent( QContextMenuEvent::Mouse,
1425                               me.pos(), me.globalPos(),
1426                               me.state() );
1427     emit contextMenuRequested( &aEvent );
1428   }
1429   if ( myOperation == FitAreaId ) {
1430     QRect rect( myPnt, me.pos() );
1431     fitArea( rect );
1432   }
1433   myPlot->canvas()->setCursor( QCursor( Qt::CrossCursor ) );
1434   myPlot->setOutlineStyle( Qwt::Triangle );
1435
1436   ((Plot2d_ViewWindow*)parent())->putInfo(tr("INF_READY"));
1437   myOperation = NoOpId;
1438 }
1439 /*!
1440   Slot, called when user wheeling mouse
1441 */
1442 void Plot2d_ViewFrame::wheelEvent(QWheelEvent* event)
1443
1444   double aDelta = event->delta();
1445   double aScale = (aDelta < 0) ? 100./(-aDelta) : aDelta/100.; 
1446
1447   QwtDiMap xMap = myPlot->canvasMap( QwtPlot::xBottom );
1448   QwtDiMap yMap = myPlot->canvasMap( QwtPlot::yLeft );
1449
1450   myPlot->setAxisScale( QwtPlot::yLeft,
1451     myPlot->invTransform( QwtPlot::yLeft, yMap.i1() ), 
1452     myPlot->invTransform( QwtPlot::yLeft, yMap.i2() )*aScale );
1453   myPlot->setAxisScale( QwtPlot::xBottom, 
1454     myPlot->invTransform( QwtPlot::xBottom, xMap.i1() ),
1455     myPlot->invTransform( QwtPlot::xBottom, xMap.i2() )*aScale );
1456   if (mySecondY) {
1457     QwtDiMap y2Map = myPlot->canvasMap( QwtPlot::yRight );
1458     myPlot->setAxisScale( QwtPlot::yRight,
1459       myPlot->invTransform( QwtPlot::yRight, y2Map.i1() ), 
1460       myPlot->invTransform( QwtPlot::yRight, y2Map.i2() )*aScale );
1461   }
1462   myPlot->replot();
1463   myPnt = event->pos();
1464 }
1465 /*!
1466   View operations : Dump view
1467 */
1468 void Plot2d_ViewFrame::onDump()
1469 {
1470   QApplication::setOverrideCursor( Qt::waitCursor );
1471   QPixmap px = QPixmap::grabWindow(winId());
1472   QApplication::restoreOverrideCursor();
1473   
1474   QString fileName = SUIT_FileDlg::getFileName(this,
1475                 QString::null,
1476                 tr("OCC_IMAGE_FILES"),
1477                 tr("INF_APP_DUMP_VIEW"),
1478                 false);
1479   if ( !fileName.isNull() )
1480   {
1481     QApplication::setOverrideCursor( Qt::waitCursor );
1482     QString fmt = SUIT_Tools::extension( fileName ).upper();
1483     if (fmt.isEmpty())
1484       fmt = QString("BMP"); // default format
1485     if (fmt == "JPG")
1486       fmt = "JPEG";
1487     bool bOk = px.save(fileName, fmt.latin1());
1488     QApplication::restoreOverrideCursor();
1489     if (!bOk) {
1490       SUIT_MessageBox::error1(this, tr("ERROR"), tr("ERR_DOC_CANT_SAVE_FILE"), tr("BUT_OK"));
1491     }
1492   }
1493 }
1494 /*!
1495   View operations : Pan view
1496 */
1497 void Plot2d_ViewFrame::onViewPan()
1498
1499   myPlot->canvas()->setCursor( panCursor );
1500   myOperation = PanId;
1501   qApp->installEventFilter( this );
1502 }
1503 /*!
1504   View operations : Zoom view
1505 */
1506 void Plot2d_ViewFrame::onViewZoom() 
1507 {
1508   myPlot->canvas()->setCursor( zoomCursor );
1509   myOperation = ZoomId;
1510   qApp->installEventFilter( this );
1511 }
1512 /*!
1513   View operations : Fot All
1514 */
1515 void Plot2d_ViewFrame::onViewFitAll() 
1516
1517   fitAll();
1518 }
1519 /*!
1520   View operations : Fit Area
1521 */
1522 void Plot2d_ViewFrame::onViewFitArea() 
1523 {
1524   myPlot->canvas()->setCursor( QCursor( Qt::PointingHandCursor ) );
1525   myOperation = FitAreaId;
1526   qApp->installEventFilter( this );
1527 }
1528 /*!
1529   View operations : Global panning
1530 */
1531 void Plot2d_ViewFrame::onViewGlobalPan() 
1532 {
1533   myPlot->canvas()->setCursor( glPanCursor );
1534   myPlot->changeAxisOptions( QwtPlot::xBottom, QwtAutoScale::Logarithmic, false );
1535   myPlot->changeAxisOptions( QwtPlot::yLeft, QwtAutoScale::Logarithmic, false );
1536   if (mySecondY)
1537     myPlot->changeAxisOptions( QwtPlot::yRight, QwtAutoScale::Logarithmic, false );
1538   myPlot->replot();
1539   QwtDiMap xMap = myPlot->canvasMap( QwtPlot::xBottom );
1540   QwtDiMap yMap = myPlot->canvasMap( QwtPlot::yLeft );
1541
1542   myXDistance = xMap.d2() - xMap.d1();
1543   myYDistance = yMap.d2() - yMap.d1();
1544
1545   if (mySecondY) {
1546     QwtDiMap yMap2 = myPlot->canvasMap( QwtPlot::yRight );
1547     myYDistance2 = yMap2.d2() - yMap2.d1();
1548   }
1549   fitAll();
1550   myOperation = GlPanId;
1551   qApp->installEventFilter( this );
1552 }
1553
1554 //=================================================================================
1555 // Plot2d_Plot2d implementation
1556 //=================================================================================
1557 /*!
1558   Constructor
1559 */
1560 Plot2d_Plot2d::Plot2d_Plot2d( QWidget* parent )
1561      : QwtPlot( parent )
1562 {
1563   // outline
1564   enableOutline( true );
1565   setOutlineStyle( Qwt::Triangle );
1566   setOutlinePen( green );
1567   // legend
1568   setAutoLegend( false );
1569   setLegendFrameStyle( QFrame::Box | QFrame::Sunken );
1570   enableLegend( false );
1571   // grid
1572   enableGridX( false );
1573   enableGridXMin( false );
1574   enableGridY( false );
1575   enableGridYMin( false );
1576   // auto scaling by default
1577   setAxisAutoScale( QwtPlot::yLeft );
1578   setAxisAutoScale( QwtPlot::yRight );
1579   setAxisAutoScale( QwtPlot::xBottom );
1580 }
1581 /*!
1582   Recalculates and redraws Plot 2d view 
1583 */
1584 void Plot2d_Plot2d::replot()
1585 {
1586   updateLayout();  // to fix bug(?) of Qwt - view is not updated when title is changed
1587   QwtPlot::replot(); 
1588 }
1589
1590 /*!
1591   Checks if two colors are close to each other [ static ]
1592   uses COLOR_DISTANCE variable as max tolerance for comparing of colors
1593 */
1594 const long COLOR_DISTANCE = 100;
1595 const int  MAX_ATTEMPTS   = 10;
1596 static bool closeColors( const QColor& color1, const QColor& color2 )
1597 {
1598   long tol = abs( color2.red()   - color1.red() ) + 
1599              abs( color2.green() - color1.green() ) +
1600        abs( color2.blue()  - color1.blue() );
1601
1602   return ( tol <= COLOR_DISTANCE );
1603 }
1604 /*!
1605   Gets new unique marker for item if possible
1606 */
1607 void Plot2d_Plot2d::getNextMarker( QwtSymbol::Style& typeMarker, QColor& color, Qt::PenStyle& typeLine ) 
1608 {
1609   bool bOk = false;
1610   int cnt = 1;
1611   while ( !bOk ) {
1612     int aRed    = (int)( 256.0 * rand() / RAND_MAX);    // generate random color
1613     int aGreen  = (int)( 256.0 * rand() / RAND_MAX);    // ...
1614     int aBlue   = (int)( 256.0 * rand() / RAND_MAX);    // ...
1615     int aMarker = (int)( 9.0 * rand() / RAND_MAX) + 1;  // 9 markers types ( not including empty )
1616     int aLine   = (int)( 5.0 * rand() / RAND_MAX) + 1;  // 5 line types ( not including empty )
1617
1618     typeMarker = ( QwtSymbol::Style )aMarker;
1619     color      = QColor( aRed, aGreen, aBlue );
1620     typeLine   = ( Qt::PenStyle )aLine;
1621
1622     cnt++;
1623     if ( cnt == MAX_ATTEMPTS )
1624       bOk = true;
1625     else
1626       bOk = !existMarker( typeMarker, color, typeLine );
1627   }
1628 /*
1629   static int aMarker = -1;
1630   static int aColor  = -1;
1631   static int aLine   = -1;
1632
1633   if ( myColors.isEmpty() ) {
1634     // creating colors list
1635     myColors.append( Qt::white );
1636     myColors.append( Qt::blue );
1637     myColors.append( Qt::gray );
1638     myColors.append( Qt::darkGreen );
1639     myColors.append( Qt::magenta );
1640     myColors.append( Qt::darkGray );
1641     myColors.append( Qt::red );
1642     myColors.append( Qt::darkBlue );
1643     myColors.append( Qt::darkYellow );
1644     myColors.append( Qt::cyan );
1645     myColors.append( Qt::darkRed );
1646     myColors.append( Qt::darkCyan );
1647     myColors.append( Qt::yellow );
1648     myColors.append( Qt::darkMagenta );
1649     myColors.append( Qt::green );
1650     myColors.append( Qt::black );
1651   }
1652
1653   int nbMarkers = 11;                   // QwtSymbol supports 11 marker types
1654   int nbLines   = 6;                    // Qt supports 6 line types
1655   int nbColors  = myColors.count();     // number of default colors supported
1656
1657   aMarker = ( aMarker + 1 ) % nbMarkers;  
1658   if ( aMarker == QwtSymbol::None || aMarker == QwtSymbol::Triangle ) aMarker++;
1659   aColor  = ( aColor  + 1 ) % nbColors;
1660   aLine   = ( aLine   + 1 ) % nbLines;    
1661   if ( aLine == Qt::NoPen ) aLine++;             
1662
1663   typeMarker = ( QwtSymbol::Style )aMarker;
1664   color      = myColors[ aColor ];
1665   typeLine   = ( Qt::PenStyle )aLine;
1666   if ( !existMarker( typeMarker, color, typeLine ) )
1667     return;
1668
1669   int i, j, k;
1670   for ( i = 0; i < nbMarkers; i++ ) {
1671     aMarker = ( aMarker + 1 ) % nbMarkers;
1672     if ( aMarker == QwtSymbol::None || aMarker == QwtSymbol::Triangle ) aMarker++;
1673     for ( j = 0; j < nbColors; j++ ) {
1674       aColor  = ( aColor  + 1 ) % nbColors;
1675       for ( k = 0; k < nbLines; k++ ) {
1676         aLine = ( aLine + 1 ) % nbLines;
1677   if ( aLine == Qt::NoPen ) aLine++;             
1678         if ( !existMarker( ( QwtSymbol::Style )aMarker, aColor, ( Qt::PenStyle )aLine ) ) {
1679           typeMarker = ( QwtSymbol::Style )aMarker;
1680           color      = myColors[ aColor ];
1681           typeLine   = ( Qt::PenStyle )aLine;
1682           return;
1683         }
1684       }
1685     }
1686   }
1687 */
1688 }
1689
1690 /*!
1691   return minimum size for qwt plot
1692 */
1693 QSize Plot2d_Plot2d::minimumSizeHint() const
1694 {
1695   QSize aSize = QwtPlot::minimumSizeHint();
1696   return QSize(aSize.width()*3/4, aSize.height());
1697 }
1698 /*!
1699   Checks if marker belongs to any enitity
1700 */
1701 bool Plot2d_Plot2d::existMarker( const QwtSymbol::Style typeMarker, const QColor& color, const Qt::PenStyle typeLine ) 
1702 {
1703   // getting all curves
1704   QArray<long> keys = curveKeys();
1705   //QColor aRgbColor;
1706
1707   if ( closeColors( color, backgroundColor() ) )
1708       return true;
1709   for ( int i = 0; i < (int)keys.count(); i++ )
1710   {
1711     QwtPlotCurve* crv = curve( keys[i] );
1712     if ( crv ) {
1713       QwtSymbol::Style aStyle = crv->symbol().style();
1714       QColor           aColor = crv->pen().color();
1715       Qt::PenStyle     aLine  = crv->pen().style();
1716 //      if ( aStyle == typeMarker && aColor == color && aLine == typeLine )
1717       if ( aStyle == typeMarker && closeColors( aColor,color ) && aLine == typeLine )
1718   return true;
1719     }
1720   }
1721   return false;
1722 }