Salome HOME
3a9b9fd4cc4b8195f891c5ca6d886919c61257e8
[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 }
1124 /*!
1125   Gets background color
1126 */
1127 QColor Plot2d_ViewFrame::backgroundColor() const
1128 {
1129   return myBackground;
1130 }
1131 /*!
1132   Sets hor.axis grid parameters
1133 */
1134 void Plot2d_ViewFrame::setXGrid( bool xMajorEnabled, const int xMajorMax, 
1135          bool xMinorEnabled, const int xMinorMax, 
1136          bool update )
1137 {
1138   myXGridMajorEnabled = xMajorEnabled;
1139   myXGridMinorEnabled = xMinorEnabled;
1140   myXGridMaxMajor = xMajorMax;
1141   myXGridMaxMinor = xMinorMax;
1142   myPlot->setAxisMaxMajor( QwtPlot::xBottom, myXGridMaxMajor );
1143   myPlot->setAxisMaxMinor( QwtPlot::xBottom, myXGridMaxMinor );
1144   myPlot->setGridXAxis(QwtPlot::xBottom);
1145   myPlot->enableGridX( myXGridMajorEnabled );
1146   myPlot->enableGridXMin( myXGridMinorEnabled );
1147   if ( update )
1148     myPlot->replot();
1149 }
1150 /*!
1151   Sets ver.axis grid parameters
1152 */
1153 void Plot2d_ViewFrame::setYGrid( bool yMajorEnabled, const int yMajorMax, 
1154                                  bool yMinorEnabled, const int yMinorMax,
1155                                  bool y2MajorEnabled, const int y2MajorMax, 
1156                                  bool y2MinorEnabled, const int y2MinorMax, 
1157                                  bool update )
1158 {
1159   myYGridMajorEnabled = yMajorEnabled;
1160   myYGridMinorEnabled = yMinorEnabled;
1161   myYGridMaxMajor = yMajorMax;
1162   myYGridMaxMinor = yMinorMax;
1163
1164   if (mySecondY) {
1165     myY2GridMajorEnabled = y2MajorEnabled;
1166     myY2GridMinorEnabled = y2MinorEnabled;
1167     myY2GridMaxMajor = y2MajorMax;
1168     myY2GridMaxMinor = y2MinorMax;
1169   }
1170   myPlot->setAxisMaxMajor( QwtPlot::yLeft, myYGridMaxMajor );
1171   myPlot->setAxisMaxMinor( QwtPlot::yLeft, myYGridMaxMinor );
1172
1173   if (mySecondY) {
1174     myPlot->setAxisMaxMajor( QwtPlot::yRight, myY2GridMaxMajor );
1175     myPlot->setAxisMaxMinor( QwtPlot::yRight, myY2GridMaxMinor );
1176   }
1177
1178   myPlot->setGridYAxis(QwtPlot::yLeft);
1179
1180   if (mySecondY) {
1181     if (myYGridMajorEnabled) {
1182       myPlot->enableGridYMin(myYGridMinorEnabled);
1183       myPlot->enableGridY( myYGridMajorEnabled);
1184     }
1185     else if (myY2GridMajorEnabled) {
1186       myPlot->setGridYAxis(QwtPlot::yRight);
1187       myPlot->enableGridYMin(myY2GridMinorEnabled);
1188       myPlot->enableGridY(myY2GridMajorEnabled);
1189     }
1190     else {
1191       myPlot->enableGridYMin(false);
1192       myPlot->enableGridY(false);
1193     }
1194   }
1195   else {
1196     myPlot->enableGridY( myYGridMajorEnabled );
1197     myPlot->enableGridYMin( myYGridMinorEnabled );
1198   }
1199   if ( update )
1200     myPlot->replot();
1201 }
1202
1203 /*!
1204   Sets title for some axis
1205 */
1206 void Plot2d_ViewFrame::setTitle( bool enabled, const QString& title,
1207                                  ObjectType type, bool update )
1208 {
1209   switch (type) {
1210     case MainTitle:
1211       myTitleEnabled = enabled;
1212       myTitle = title;
1213       myPlot->setTitle( myTitleEnabled ? myTitle : QString::null );
1214       break;
1215     case XTitle:
1216       myXTitleEnabled = enabled;
1217       myXTitle = title;
1218       myPlot->setAxisTitle( QwtPlot::xBottom, myXTitleEnabled ? myXTitle : QString::null );
1219       break;
1220     case YTitle:
1221       myYTitleEnabled = enabled;
1222       myYTitle = title;
1223       myPlot->setAxisTitle( QwtPlot::yLeft, myYTitleEnabled ? myYTitle : QString::null );
1224       break;
1225     case Y2Title:
1226       myY2TitleEnabled = enabled;
1227       myY2Title = title;
1228       myPlot->setAxisTitle( QwtPlot::yRight, myY2TitleEnabled ? myY2Title : QString::null );
1229       break;
1230   }
1231   if ( update )
1232     myPlot->replot();
1233 }
1234 /*!
1235   Sets title for some axis
1236 */
1237 QString Plot2d_ViewFrame::getTitle( ObjectType type ) const
1238 {
1239   QString title = "";
1240   switch (type) {
1241     case MainTitle:
1242       title = myTitle;   break;
1243     case XTitle:
1244       title = myXTitle;  break;
1245     case YTitle:
1246       title = myYTitle;  break;
1247     case Y2Title:
1248       title = myY2Title; break;
1249   }
1250   return title;
1251 }
1252 /*!
1253   Sets font for Plot2d object : title or axis
1254 */
1255 void Plot2d_ViewFrame::setFont( const QFont& font, ObjectType type, bool update)
1256 {
1257   switch (type) {
1258     case MainTitle:
1259       myPlot->setTitleFont(font);
1260       break;
1261     case XTitle:
1262       myPlot->setAxisTitleFont(QwtPlot::xBottom, font); break;
1263     case YTitle:
1264       myPlot->setAxisTitleFont(QwtPlot::yLeft, font);   break;
1265     case Y2Title:
1266       myPlot->setAxisTitleFont(QwtPlot::yRight, font);  break;
1267     case XAxis:
1268       myPlot->setAxisFont(QwtPlot::xBottom, font);      break;
1269     case YAxis:
1270       myPlot->setAxisFont(QwtPlot::yLeft, font);        break;
1271     case Y2Axis:
1272       myPlot->setAxisFont(QwtPlot::yRight, font);       break;
1273   }
1274   if ( update )
1275     myPlot->replot();
1276 }
1277 /*!
1278   Sets scale mode for horizontal axis: 0 - linear, 1 - logarithmic
1279 */
1280 void Plot2d_ViewFrame::setHorScaleMode( const int mode, bool update )
1281 {
1282   myXMode = mode;
1283   if ( myXMode == 0 ) // linear
1284     myPlot->changeAxisOptions( QwtPlot::xBottom, QwtAutoScale::Logarithmic, false );
1285   else                // logarithmic
1286     myPlot->changeAxisOptions( QwtPlot::xBottom, QwtAutoScale::Logarithmic, true );
1287
1288   if ( update )
1289     fitAll();
1290   emit vpModeHorChanged();
1291 }
1292 /*!
1293   Sets scale mode for vertical axis: 0 - linear, 1 - logarithmic
1294 */
1295 void Plot2d_ViewFrame::setVerScaleMode( const int mode, bool update )
1296 {
1297   myYMode = mode;
1298   if ( myYMode == 0 ) { // linear
1299     myPlot->changeAxisOptions( QwtPlot::yLeft, QwtAutoScale::Logarithmic, false );
1300     if (mySecondY)
1301       myPlot->changeAxisOptions( QwtPlot::yRight, QwtAutoScale::Logarithmic, false );
1302   }
1303   else {               // logarithmic
1304     myPlot->changeAxisOptions( QwtPlot::yLeft, QwtAutoScale::Logarithmic, true );
1305     if (mySecondY)
1306       myPlot->changeAxisOptions( QwtPlot::yRight, QwtAutoScale::Logarithmic, true );
1307   }
1308   if ( update )
1309     fitAll();
1310   emit vpModeVerChanged();
1311 }
1312
1313 /*!
1314   Return, scale mode for horizontal axis
1315 */
1316 bool Plot2d_ViewFrame::isModeHorLinear()
1317 {
1318   return (myXMode == 0 ? true : false);
1319 }
1320
1321 /*!
1322   Return, scale mode for vertical axis
1323 */
1324 bool Plot2d_ViewFrame::isModeVerLinear()
1325 {
1326   return (myYMode == 0 ? true : false);
1327 }
1328 /*!
1329   Slot, called when user presses mouse button
1330 */
1331 void Plot2d_ViewFrame::plotMousePressed(const QMouseEvent& me )
1332 {
1333   if ( myOperation == NoOpId )
1334     myOperation = testOperation( me );
1335   if ( myOperation != NoOpId ) {
1336     myPnt = me.pos();
1337     if ( myOperation == FitAreaId ) {
1338       myPlot->setOutlineStyle( Qwt::Rect );
1339     }
1340     else if ( myOperation == GlPanId ) {
1341       myPlot->setAxisScale( QwtPlot::yLeft,
1342           myPlot->invTransform( QwtPlot::yLeft, myPnt.y() ) + myYDistance/2, 
1343           myPlot->invTransform( QwtPlot::yLeft, myPnt.y() ) - myYDistance/2 );
1344       myPlot->setAxisScale( QwtPlot::xBottom, 
1345           myPlot->invTransform( QwtPlot::xBottom, myPnt.x() ) - myXDistance/2, 
1346           myPlot->invTransform( QwtPlot::xBottom, myPnt.x() ) + myXDistance/2 );
1347       if (mySecondY)
1348         myPlot->setAxisScale( QwtPlot::yRight,
1349           myPlot->invTransform( QwtPlot::yRight, myPnt.y() ) + myYDistance2/2, 
1350           myPlot->invTransform( QwtPlot::yRight, myPnt.y() ) - myYDistance2/2 );
1351       myPlot->replot();
1352     }
1353   }
1354   else {
1355     int btn = me.button() | me.state();
1356     if (btn == RightButton) {
1357       QMouseEvent* aEvent = new QMouseEvent(QEvent::MouseButtonPress,
1358                                             me.pos(), btn, me.state());
1359       // QMouseEvent 'me' has the 'MouseButtonDblClick' type. In this case we create new event 'aEvent'.
1360       parent()->eventFilter(this, aEvent);
1361     }
1362   }
1363 }
1364 /*!
1365   Slot, called when user moves mouse
1366 */
1367 void Plot2d_ViewFrame::plotMouseMoved( const QMouseEvent& me )
1368 {
1369   int    dx = me.pos().x() - myPnt.x();
1370   int    dy = me.pos().y() - myPnt.y();
1371
1372   if ( myOperation != NoOpId) {
1373     if ( myOperation == ZoomId ) {
1374       QwtDiMap xMap = myPlot->canvasMap( QwtPlot::xBottom );
1375       QwtDiMap yMap = myPlot->canvasMap( QwtPlot::yLeft );
1376
1377       myPlot->setAxisScale( QwtPlot::yLeft, 
1378           myPlot->invTransform( QwtPlot::yLeft, yMap.i1() ), 
1379           myPlot->invTransform( QwtPlot::yLeft, yMap.i2() + dy ) );
1380       myPlot->setAxisScale( QwtPlot::xBottom, 
1381           myPlot->invTransform( QwtPlot::xBottom, xMap.i1() ), 
1382           myPlot->invTransform( QwtPlot::xBottom, xMap.i2() - dx ) );
1383       if (mySecondY) {
1384         QwtDiMap y2Map = myPlot->canvasMap( QwtPlot::yRight );
1385         myPlot->setAxisScale( QwtPlot::yRight, 
1386           myPlot->invTransform( QwtPlot::yRight, y2Map.i1() ), 
1387           myPlot->invTransform( QwtPlot::yRight, y2Map.i2() + dy ) );
1388       }
1389       myPlot->replot();
1390       myPnt = me.pos();
1391     }
1392     else if ( myOperation == PanId ) {
1393       QwtDiMap xMap = myPlot->canvasMap( QwtPlot::xBottom );
1394       QwtDiMap yMap = myPlot->canvasMap( QwtPlot::yLeft );
1395
1396       myPlot->setAxisScale( QwtPlot::yLeft, 
1397           myPlot->invTransform( QwtPlot::yLeft, yMap.i1()-dy ), 
1398           myPlot->invTransform( QwtPlot::yLeft, yMap.i2()-dy ) );
1399       myPlot->setAxisScale( QwtPlot::xBottom, 
1400           myPlot->invTransform( QwtPlot::xBottom, xMap.i1()-dx ),
1401           myPlot->invTransform( QwtPlot::xBottom, xMap.i2()-dx ) ); 
1402       if (mySecondY) {
1403         QwtDiMap y2Map = myPlot->canvasMap( QwtPlot::yRight );
1404         myPlot->setAxisScale( QwtPlot::yRight,
1405           myPlot->invTransform( QwtPlot::yRight, y2Map.i1()-dy ), 
1406           myPlot->invTransform( QwtPlot::yRight, y2Map.i2()-dy ) );
1407       }
1408       myPlot->replot();
1409       myPnt = me.pos();
1410     }
1411   }
1412   else {
1413     ((Plot2d_ViewWindow*)parent())->putInfo(getInfo(me.pos()));
1414   }
1415 }
1416 /*!
1417   Slot, called when user releases mouse
1418 */
1419 void Plot2d_ViewFrame::plotMouseReleased( const QMouseEvent& me )
1420 {
1421   if ( myOperation == NoOpId && me.button() == RightButton )
1422   {
1423     QContextMenuEvent aEvent( QContextMenuEvent::Mouse,
1424                               me.pos(), me.globalPos(),
1425                               me.state() );
1426     emit contextMenuRequested( &aEvent );
1427   }
1428   if ( myOperation == FitAreaId ) {
1429     QRect rect( myPnt, me.pos() );
1430     fitArea( rect );
1431   }
1432   myPlot->canvas()->setCursor( QCursor( Qt::CrossCursor ) );
1433   myPlot->setOutlineStyle( Qwt::Triangle );
1434
1435   ((Plot2d_ViewWindow*)parent())->putInfo(tr("INF_READY"));
1436   myOperation = NoOpId;
1437 }
1438 /*!
1439   Slot, called when user wheeling mouse
1440 */
1441 void Plot2d_ViewFrame::wheelEvent(QWheelEvent* event)
1442
1443   double aDelta = event->delta();
1444   double aScale = (aDelta < 0) ? 100./(-aDelta) : aDelta/100.; 
1445
1446   QwtDiMap xMap = myPlot->canvasMap( QwtPlot::xBottom );
1447   QwtDiMap yMap = myPlot->canvasMap( QwtPlot::yLeft );
1448
1449   myPlot->setAxisScale( QwtPlot::yLeft,
1450     myPlot->invTransform( QwtPlot::yLeft, yMap.i1() ), 
1451     myPlot->invTransform( QwtPlot::yLeft, yMap.i2() )*aScale );
1452   myPlot->setAxisScale( QwtPlot::xBottom, 
1453     myPlot->invTransform( QwtPlot::xBottom, xMap.i1() ),
1454     myPlot->invTransform( QwtPlot::xBottom, xMap.i2() )*aScale );
1455   if (mySecondY) {
1456     QwtDiMap y2Map = myPlot->canvasMap( QwtPlot::yRight );
1457     myPlot->setAxisScale( QwtPlot::yRight,
1458       myPlot->invTransform( QwtPlot::yRight, y2Map.i1() ), 
1459       myPlot->invTransform( QwtPlot::yRight, y2Map.i2() )*aScale );
1460   }
1461   myPlot->replot();
1462   myPnt = event->pos();
1463 }
1464 /*!
1465   View operations : Dump view
1466 */
1467 void Plot2d_ViewFrame::onDump()
1468 {
1469   QApplication::setOverrideCursor( Qt::waitCursor );
1470   QPixmap px = QPixmap::grabWindow(winId());
1471   QApplication::restoreOverrideCursor();
1472   
1473   QString fileName = SUIT_FileDlg::getFileName(this,
1474                 QString::null,
1475                 tr("OCC_IMAGE_FILES"),
1476                 tr("INF_APP_DUMP_VIEW"),
1477                 false);
1478   if ( !fileName.isNull() )
1479   {
1480     QApplication::setOverrideCursor( Qt::waitCursor );
1481     QString fmt = SUIT_Tools::extension( fileName ).upper();
1482     if (fmt.isEmpty())
1483       fmt = QString("BMP"); // default format
1484     if (fmt == "JPG")
1485       fmt = "JPEG";
1486     bool bOk = px.save(fileName, fmt.latin1());
1487     QApplication::restoreOverrideCursor();
1488     if (!bOk) {
1489       SUIT_MessageBox::error1(this, tr("ERROR"), tr("ERR_DOC_CANT_SAVE_FILE"), tr("BUT_OK"));
1490     }
1491   }
1492 }
1493 /*!
1494   View operations : Pan view
1495 */
1496 void Plot2d_ViewFrame::onViewPan()
1497
1498   myPlot->canvas()->setCursor( panCursor );
1499   myOperation = PanId;
1500   qApp->installEventFilter( this );
1501 }
1502 /*!
1503   View operations : Zoom view
1504 */
1505 void Plot2d_ViewFrame::onViewZoom() 
1506 {
1507   myPlot->canvas()->setCursor( zoomCursor );
1508   myOperation = ZoomId;
1509   qApp->installEventFilter( this );
1510 }
1511 /*!
1512   View operations : Fot All
1513 */
1514 void Plot2d_ViewFrame::onViewFitAll() 
1515
1516   fitAll();
1517 }
1518 /*!
1519   View operations : Fit Area
1520 */
1521 void Plot2d_ViewFrame::onViewFitArea() 
1522 {
1523   myPlot->canvas()->setCursor( QCursor( Qt::PointingHandCursor ) );
1524   myOperation = FitAreaId;
1525   qApp->installEventFilter( this );
1526 }
1527 /*!
1528   View operations : Global panning
1529 */
1530 void Plot2d_ViewFrame::onViewGlobalPan() 
1531 {
1532   myPlot->canvas()->setCursor( glPanCursor );
1533   myPlot->changeAxisOptions( QwtPlot::xBottom, QwtAutoScale::Logarithmic, false );
1534   myPlot->changeAxisOptions( QwtPlot::yLeft, QwtAutoScale::Logarithmic, false );
1535   if (mySecondY)
1536     myPlot->changeAxisOptions( QwtPlot::yRight, QwtAutoScale::Logarithmic, false );
1537   myPlot->replot();
1538   QwtDiMap xMap = myPlot->canvasMap( QwtPlot::xBottom );
1539   QwtDiMap yMap = myPlot->canvasMap( QwtPlot::yLeft );
1540
1541   myXDistance = xMap.d2() - xMap.d1();
1542   myYDistance = yMap.d2() - yMap.d1();
1543
1544   if (mySecondY) {
1545     QwtDiMap yMap2 = myPlot->canvasMap( QwtPlot::yRight );
1546     myYDistance2 = yMap2.d2() - yMap2.d1();
1547   }
1548   fitAll();
1549   myOperation = GlPanId;
1550   qApp->installEventFilter( this );
1551 }
1552
1553 //=================================================================================
1554 // Plot2d_Plot2d implementation
1555 //=================================================================================
1556 /*!
1557   Constructor
1558 */
1559 Plot2d_Plot2d::Plot2d_Plot2d( QWidget* parent )
1560      : QwtPlot( parent )
1561 {
1562   // outline
1563   enableOutline( true );
1564   setOutlineStyle( Qwt::Triangle );
1565   setOutlinePen( green );
1566   // legend
1567   setAutoLegend( false );
1568   setLegendFrameStyle( QFrame::Box | QFrame::Sunken );
1569   enableLegend( false );
1570   // grid
1571   enableGridX( false );
1572   enableGridXMin( false );
1573   enableGridY( false );
1574   enableGridYMin( false );
1575   // auto scaling by default
1576   setAxisAutoScale( QwtPlot::yLeft );
1577   setAxisAutoScale( QwtPlot::yRight );
1578   setAxisAutoScale( QwtPlot::xBottom );
1579 }
1580 /*!
1581   Recalculates and redraws Plot 2d view 
1582 */
1583 void Plot2d_Plot2d::replot()
1584 {
1585   updateLayout();  // to fix bug(?) of Qwt - view is not updated when title is changed
1586   QwtPlot::replot(); 
1587 }
1588
1589 /*!
1590   Checks if two colors are close to each other [ static ]
1591   uses COLOR_DISTANCE variable as max tolerance for comparing of colors
1592 */
1593 const long COLOR_DISTANCE = 100;
1594 const int  MAX_ATTEMPTS   = 10;
1595 static bool closeColors( const QColor& color1, const QColor& color2 )
1596 {
1597   long tol = abs( color2.red()   - color1.red() ) + 
1598              abs( color2.green() - color1.green() ) +
1599        abs( color2.blue()  - color1.blue() );
1600
1601   return ( tol <= COLOR_DISTANCE );
1602 }
1603 /*!
1604   Gets new unique marker for item if possible
1605 */
1606 void Plot2d_Plot2d::getNextMarker( QwtSymbol::Style& typeMarker, QColor& color, Qt::PenStyle& typeLine ) 
1607 {
1608   bool bOk = false;
1609   int cnt = 1;
1610   while ( !bOk ) {
1611     int aRed    = (int)( 256.0 * rand() / RAND_MAX);    // generate random color
1612     int aGreen  = (int)( 256.0 * rand() / RAND_MAX);    // ...
1613     int aBlue   = (int)( 256.0 * rand() / RAND_MAX);    // ...
1614     int aMarker = (int)( 9.0 * rand() / RAND_MAX) + 1;  // 9 markers types ( not including empty )
1615     int aLine   = (int)( 5.0 * rand() / RAND_MAX) + 1;  // 5 line types ( not including empty )
1616
1617     typeMarker = ( QwtSymbol::Style )aMarker;
1618     color      = QColor( aRed, aGreen, aBlue );
1619     typeLine   = ( Qt::PenStyle )aLine;
1620
1621     cnt++;
1622     if ( cnt == MAX_ATTEMPTS )
1623       bOk = true;
1624     else
1625       bOk = !existMarker( typeMarker, color, typeLine );
1626   }
1627 /*
1628   static int aMarker = -1;
1629   static int aColor  = -1;
1630   static int aLine   = -1;
1631
1632   if ( myColors.isEmpty() ) {
1633     // creating colors list
1634     myColors.append( Qt::white );
1635     myColors.append( Qt::blue );
1636     myColors.append( Qt::gray );
1637     myColors.append( Qt::darkGreen );
1638     myColors.append( Qt::magenta );
1639     myColors.append( Qt::darkGray );
1640     myColors.append( Qt::red );
1641     myColors.append( Qt::darkBlue );
1642     myColors.append( Qt::darkYellow );
1643     myColors.append( Qt::cyan );
1644     myColors.append( Qt::darkRed );
1645     myColors.append( Qt::darkCyan );
1646     myColors.append( Qt::yellow );
1647     myColors.append( Qt::darkMagenta );
1648     myColors.append( Qt::green );
1649     myColors.append( Qt::black );
1650   }
1651
1652   int nbMarkers = 11;                   // QwtSymbol supports 11 marker types
1653   int nbLines   = 6;                    // Qt supports 6 line types
1654   int nbColors  = myColors.count();     // number of default colors supported
1655
1656   aMarker = ( aMarker + 1 ) % nbMarkers;  
1657   if ( aMarker == QwtSymbol::None || aMarker == QwtSymbol::Triangle ) aMarker++;
1658   aColor  = ( aColor  + 1 ) % nbColors;
1659   aLine   = ( aLine   + 1 ) % nbLines;    
1660   if ( aLine == Qt::NoPen ) aLine++;             
1661
1662   typeMarker = ( QwtSymbol::Style )aMarker;
1663   color      = myColors[ aColor ];
1664   typeLine   = ( Qt::PenStyle )aLine;
1665   if ( !existMarker( typeMarker, color, typeLine ) )
1666     return;
1667
1668   int i, j, k;
1669   for ( i = 0; i < nbMarkers; i++ ) {
1670     aMarker = ( aMarker + 1 ) % nbMarkers;
1671     if ( aMarker == QwtSymbol::None || aMarker == QwtSymbol::Triangle ) aMarker++;
1672     for ( j = 0; j < nbColors; j++ ) {
1673       aColor  = ( aColor  + 1 ) % nbColors;
1674       for ( k = 0; k < nbLines; k++ ) {
1675         aLine = ( aLine + 1 ) % nbLines;
1676   if ( aLine == Qt::NoPen ) aLine++;             
1677         if ( !existMarker( ( QwtSymbol::Style )aMarker, aColor, ( Qt::PenStyle )aLine ) ) {
1678           typeMarker = ( QwtSymbol::Style )aMarker;
1679           color      = myColors[ aColor ];
1680           typeLine   = ( Qt::PenStyle )aLine;
1681           return;
1682         }
1683       }
1684     }
1685   }
1686 */
1687 }
1688
1689 /*!
1690   return minimum size for qwt plot
1691 */
1692 QSize Plot2d_Plot2d::minimumSizeHint() const
1693 {
1694   QSize aSize = QwtPlot::minimumSizeHint();
1695   return QSize(aSize.width()*3/4, aSize.height());
1696 }
1697 /*!
1698   Checks if marker belongs to any enitity
1699 */
1700 bool Plot2d_Plot2d::existMarker( const QwtSymbol::Style typeMarker, const QColor& color, const Qt::PenStyle typeLine ) 
1701 {
1702   // getting all curves
1703   QArray<long> keys = curveKeys();
1704   //QColor aRgbColor;
1705
1706   if ( closeColors( color, backgroundColor() ) )
1707       return true;
1708   for ( int i = 0; i < (int)keys.count(); i++ )
1709   {
1710     QwtPlotCurve* crv = curve( keys[i] );
1711     if ( crv ) {
1712       QwtSymbol::Style aStyle = crv->symbol().style();
1713       QColor           aColor = crv->pen().color();
1714       Qt::PenStyle     aLine  = crv->pen().style();
1715 //      if ( aStyle == typeMarker && aColor == color && aLine == typeLine )
1716       if ( aStyle == typeMarker && closeColors( aColor,color ) && aLine == typeLine )
1717   return true;
1718     }
1719   }
1720   return false;
1721 }