CMS 3D CMS Logo

Ig3DBaseBrowser.cc

Go to the documentation of this file.
00001 #include "Iguana/GLBrowsers/interface/Ig3DBaseBrowser.h"
00002 #include "Iguana/GLBrowsers/interface/xtypeinfo.h"
00003 #include "Iguana/GLModels/interface/Ig3DBaseModel.h"
00004 #include "Iguana/GLModels/interface/Ig3DBaseModelEvent.h"
00005 #include "Iguana/GLModels/interface/Ig3DBaseRep.h"
00006 #include "Iguana/GLBrowsers/interface/Ig3DSystem.h"
00007 #include "Iguana/Studio/interface/IgQtAppStatusBarService.h"
00008 #include "Iguana/Studio/interface/IgQtSite.h"
00009 #include "Iguana/Studio/interface/IgQtObjectMenuService.h"
00010 #include "Iguana/Studio/interface/IgQtObjectMenuMessage.h"
00011 #include "Iguana/Studio/interface/IgQtObjectMenu.h"
00012 #include "Iguana/Inventor/interface/IgSoGL2PSAction.h"
00013 #include "Iguana/Inventor/interface/IgSoGridPlane.h"
00014 #include "Iguana/Framework/interface/IgRepSet.h"
00015 #include "Iguana/Framework/interface/IgRepContext.h"
00016 #include "Iguana/Framework/interface/IgSelectionService.h"
00017 #include "Iguana/Framework/interface/IgSelectionMessage.h"
00018 #include "Iguana/Framework/interface/xtypeinfo.h"
00019 #include "Iguana/Framework/interface/IgExtensionDB.h"
00020 #include <climits>
00021 #include <qhbox.h>
00022 #include <qwidget.h>
00023 #include <qmenubar.h>
00024 #include <qpopupmenu.h>
00025 #include <qfiledialog.h>
00026 #include <qcolordialog.h>
00027 #include <qinputdialog.h>
00028 #include <qbuttongroup.h>
00029 #include <qlayout.h>
00030 #include <qtooltip.h>
00031 #include <qwhatsthis.h>
00032 #include <qvbox.h>
00033 #include <qapplication.h>
00034 #include <qmessagebox.h>
00035 #include <qdir.h>
00036 #include <qfileinfo.h>
00037 #include <qcursor.h>
00038 #include <Inventor/Qt/SoQtCursor.h>
00039 #include <Inventor/SoPath.h>
00040 #include <Inventor/SbLinear.h>
00041 #include <Inventor/SoInput.h>
00042 #include <Inventor/SoPickedPoint.h>
00043 #include <Inventor/SoOffscreenRenderer.h>
00044 #include <Inventor/nodes/SoGroup.h>
00045 #include <Inventor/nodes/SoSelection.h>
00046 #include <Inventor/nodes/SoPerspectiveCamera.h>
00047 #include <Inventor/nodes/SoOrthographicCamera.h>
00048 #include <Inventor/nodes/SoClipPlane.h>
00049 #include <Inventor/actions/SoLineHighlightRenderAction.h>
00050 #include <Inventor/actions/SoBoxHighlightRenderAction.h>
00051 #include <Inventor/actions/SoSearchAction.h>
00052 #include <Inventor/actions/SoWriteAction.h>
00053 #include <Inventor/actions/SoSearchAction.h>
00054 #include <Inventor/actions/SoGetBoundingBoxAction.h>
00055 #include <Inventor/sensors/SoFieldSensor.h>
00056 #include <Inventor/Qt/SoQt.h>
00057 #include "Iguana/GL2PS/interface/gl2ps.h"
00058 
00059 #undef emit /* FIXME: disgusting hack: qt defines `emit' as a macro */
00060 #include <classlib/utils/Callback.h>
00061 #include <classlib/utils/DebugAids.h>
00062 #include <classlib/iobase/Filename.h>
00063 #include <classlib/utils/Log.h>
00064 #include <typeinfo>
00065 
00066 // Button index values.
00067 enum {
00068     INTERACT_BUTTON = 0,
00069     EXAMINE_BUTTON,
00070     HOME_BUTTON,
00071     SET_HOME_BUTTON,
00072     VIEW_ALL_BUTTON,
00073     SEEK_BUTTON,
00074     CAMERA_BUTTON
00075 };
00076 
00077 lat::logflag LF3dbrowser = { 0, "3dbrowser", true, -1 };
00078 
00079 // NB: We create an intermediate widget for geometry management due
00080 // SoQt's resizing logic.  It seems that SoQt doesn't actually react
00081 // to resize events, but depends on an event filter to spy the parent
00082 // widget resize events.  This means that as a child of a splitter (or
00083 // anything else that subdivides its own area) things will go awfully
00084 // wrong.  Hence we give an intermediate QHBox for layout management
00085 // (a QWidget won't do).
00086 
00087 QWidget *
00088 Ig3DBaseBrowser::initialise (IgState *state, IgSite *site)
00089 {
00090     // Ig3DBaseBrowser inherits SoQtExaminerViewer.  However, we need to
00091     // initialise the 3D subsystem properly before creating the
00092     // viewer.  Thus we need to run a special between the entering of
00093     // the Ig3DBaseBrowser constructor and before running the base class
00094     // (SoQtExaminerViewer) constructor.  This function is that magic
00095     // initialiser hook.  The return value is the geometry-managing
00096     // parent widget for the examiner window (see the comment above
00097     // for the details).
00098 
00099     // Initialise SoQt if it hasn't been done yet.
00100     Ig3DSystem::init (state, IgQtSite::selfFrom (site)->topLevelWidget ());
00101 
00102     // Return the magic intermediate widget parent to manage geometry.
00103     QWidget *w = new QWidget (IgQtSite::hostFrom (site));
00104     (new QVBoxLayout (w))->setAutoAdd (true);
00105     QSize size = IgQtSite::hostFrom (site)->size();
00106     if (size.width () > 1)
00107         w->resize (size);
00108     return w;
00109 }
00110 
00111 // `init' allows us to use SoQt widgets and Inventor so initialise the
00112 // base class and the data members.
00113 Ig3DBaseBrowser::Ig3DBaseBrowser (IgState *state, 
00114                                   IgSite *site, 
00115                                   Ig3DBaseModel *model)
00116     : SoQtExaminerViewer (initialise (state, site), "3D Browser",
00117                           true, BUILD_ALL, BROWSER, false),
00118       m_state (new IgState (state)),
00119       m_model (model),
00120       m_selection (0),
00121       m_menuRep (0), 
00122       m_first_time (true),
00123       m_grid (false),
00124       m_gl2psOptions (GL2PS_SIMPLE_LINE_OFFSET 
00125                       | GL2PS_BEST_ROOT
00126                       | GL2PS_OCCLUSION_CULL),
00127       m_currentPick (0),
00128       m_whatsThisPicking (false),
00129       m_oldView (true),
00130       m_oldSeek (false),
00131       m_gl2psFBBufferSize (1024*1024),
00132       m_farDistanceSensor (0),
00133       m_nearDistanceSensor (0)
00134 {
00135     initWidget (site);
00136     //FIXME: remove when SoQt fixes the continious rendering problem
00137     //create sersors to sence the near and for clip plane distance and
00138     //force them to be 0.1 and SHRT_MAX
00139     SoCamera * const camera = SoQtExaminerViewer::getCamera ();
00140 
00141     ASSERT (camera);
00142     camera->farDistance  = SHRT_MAX;
00143     camera->nearDistance  = 0.1;
00144     m_farDistanceSensor = new SoFieldSensor (&farDistanceSensorCB, this);
00145     m_farDistanceSensor->attach (&camera->farDistance);
00146     m_nearDistanceSensor = new SoFieldSensor (&nearDistanceSensorCB, this);
00147     m_nearDistanceSensor->attach (&camera->nearDistance);
00148 
00149     SoNode *node = model->attachPoint ()->findMagic (
00150         Ig3DBaseModel::encode ("Default Grid Group"));
00151     if (node && dynamic_cast<SoGroup*>(node)->getNumChildren ())
00152         m_grid = true;
00153 }
00154 
00155 SbBool
00156 Ig3DBaseBrowser::eventCallback (void *closure, QEvent *event)
00157 {
00158     Ig3DBaseBrowser *self = static_cast<Ig3DBaseBrowser *> (closure);
00159     if (!self->getParentWidget()->hasMouse () ||
00160         !self->isViewing())
00161         return false;
00162 
00163     if (QWheelEvent *wheelEvent = dynamic_cast<QWheelEvent *> (event))
00164     {
00165         self->zoom (0.1 * (wheelEvent->delta () > 0 ? 1:-1));
00166         return true;
00167     }
00168     else if (QMouseEvent *mEvent = dynamic_cast<QMouseEvent *> (event))
00169     {
00170         if (mEvent->button () == Qt::LeftButton
00171             &&  mEvent->type () == QEvent::MouseButtonRelease
00172             && self->isSeekMode())
00173         {
00174             self->setComponentCursor (SoQtCursor::getRotateCursor ());
00175             return true;
00176         }
00177         return false;
00178     }
00179     return false;
00180 }
00181 
00182 void
00183 Ig3DBaseBrowser::initWidget (IgSite *site)
00184 {
00185     ASSERT (m_model);
00186     // Host in the site and decorate the viewer with more buttons.
00187     IgQtSite::host (site, getParentWidget ());
00188     setBaseWidget (buildWidget (getParentWidget ()));
00189 
00190     // FIXME: from cmscan
00191     // setBottomWheelString ("Rot Z");
00192     // parent->setIcon (QPixmap (cmsLogo_xpm));
00193 
00194     // Hook on the selection service
00195     ASSERT (IgSelectionService::get (m_state));
00196     IgSelectionService::get (m_state)
00197         ->add (lat::CreateCallback (this, &Ig3DBaseBrowser::selectMessage));
00198     m_model->listen (Ig3DBaseModel::ModelChanged,
00199                      lat::CreateCallback (this, &Ig3DBaseBrowser::modelChanged));
00200 
00201     // Make the model the scene graph.  Note that the model always has
00202     // a hidden root whether or not it contains anything.
00203     SoGroup *graph = m_model->sceneGraph ();
00204     ASSERT (graph);
00205     setSceneGraph (graph);
00206 
00207     // Put selection hooks on the scene graph.  The know that the
00208     // model's hidden root is always a SoSelection.
00209     ASSERT (graph->isOfType (SoSelection::getClassTypeId ()));
00210     SoSelection *top = static_cast<SoSelection *> (graph);
00211     top->policy.setValue (SoSelection::SINGLE);
00212 
00213     redrawOnSelectionChange (top);
00214     setGLRenderAction (new SoLineHighlightRenderAction);
00215     setEventCallback (eventCallback, this);
00216 
00217     // Make myself visible: get SoQt to do some preparations.
00218     show ();
00219 }
00220 
00221 void
00222 Ig3DBaseBrowser::focusIn (void)
00223 {
00224     // Make the model the scene graph.  Note that the model always has
00225     // a hidden root whether or not it contains anything.
00226     SoSelection *top = static_cast<SoSelection *> (m_model->sceneGraph ());
00227     top->setPickFilterCallback (onPick, this);
00228     top->addSelectionCallback (onSelect, this);
00229     top->addDeselectionCallback (onDeselect, this);
00230 }
00231 
00232 void
00233 Ig3DBaseBrowser::focusOut (void)
00234 {
00235     SoSelection *top = static_cast<SoSelection *> (m_model->sceneGraph ());
00236     top->removeSelectionCallback (onSelect, this);
00237     top->removeDeselectionCallback (onDeselect, this);
00238 }
00239 
00243 void
00244 Ig3DBaseBrowser::createViewerButtons (QWidget* parent, SbPList* buttonlist)
00245 {
00246     SoQtExaminerViewer::createViewerButtons (parent, buttonlist);
00247 
00248     // Are there any buttons?
00249     int nrbuttons = buttonlist->getLength();
00250     if (nrbuttons == 0) return;
00251 
00252     QToolTip::add ((QWidget*) ((*buttonlist ) [INTERACT_BUTTON]), "Select/Pick");
00253     QWhatsThis::add ((QWidget*) ((*buttonlist) [INTERACT_BUTTON]), 
00254                      tr ("<b>Select/Pick Button:</b>\n"
00255                          "Selects object manipulation or pick mode \n"
00256                          "(and deselects camera or viewer mode).\n"
00257                          "The cursor shape will change to an arrow.\n"
00258                          "In this mode, the user is manipulating objects\n"
00259                          "in the scene graph."));
00260 
00261     QToolTip::add ((QWidget*) ((*buttonlist ) [EXAMINE_BUTTON]), "View");
00262     QWhatsThis::add ((QWidget*) ((*buttonlist) [EXAMINE_BUTTON]),
00263                      tr ("<b>View Button:</b>\n"
00264                          "Selects camera or viewer mode (and deselects object \n"
00265                          "manipulation or pick mode). The cursor shape will\n"
00266                          "change to a circular arrows icon. In this mode,\n"
00267                          "the user is moving the camera in 3D space."));
00268         
00269     QToolTip::add ((QWidget*) ((*buttonlist ) [HOME_BUTTON]), "Home");
00270     QWhatsThis::add ((QWidget*) ((*buttonlist) [HOME_BUTTON]),
00271                      tr ("<b>Home Button:</b>\n"
00272                          "Returns the camera to its home position\n"
00273                          "(initial position if not reset)."));
00274     
00275     QToolTip::add ((QWidget*) ((*buttonlist ) [SET_HOME_BUTTON]), "Set Home");
00276     QWhatsThis::add ((QWidget*) ((*buttonlist) [SET_HOME_BUTTON]),
00277                      tr ("<b>Set Home Button:</b>\n"
00278                          "Resets the home position to the current\n"
00279                          "camera position."));
00280 
00281     QToolTip::add ((QWidget*) ((*buttonlist ) [VIEW_ALL_BUTTON]), "View All");
00282     QWhatsThis::add ((QWidget*) ((*buttonlist) [VIEW_ALL_BUTTON]),
00283                      tr ("<b>View All Button:</b>\n"
00284                          "Brings the entire scene graph into view."));
00285     
00286     QToolTip::add ((QWidget*) ((*buttonlist ) [SEEK_BUTTON]), "Seek");
00287     QWhatsThis::add ((QWidget*) ((*buttonlist) [SEEK_BUTTON]),
00288                      tr ("<b>Seek Button:</b>\n"
00289                          "Allows the user to select a new center\n"
00290                          "of rotation for the camera. When clicked\n"
00291                          "on (and in viewer mode) the cursor changes\n"
00292                          "to a crosshair. The next left mouse\n"
00293                          "buttonpress causes whatever is underneath\n"
00294                          "the cursor to be selected as the new center\n"
00295                          "of rotation. Once the button is released,\n"
00296                          "the camera either jumps or animates to its\n"
00297                          "new position depending on the current\n"
00298                          "setting of the seek time in the preferences\n"
00299                          "dialog box."));
00300     
00301     QToolTip::add ((QWidget*) ((*buttonlist ) [CAMERA_BUTTON]), "Projection");
00302     QWhatsThis::add ((QWidget*) ((*buttonlist) [CAMERA_BUTTON]),
00303                      tr ("<b>Projection Button:</b>\n"
00304                          "Selects the type of camera used\n"
00305                          "by the viewer. It toggles between\n"
00306                          "the two available camera types -\n"
00307                          "perspective and orthographic."));
00308 }
00309 
00310 QWidget *
00311 Ig3DBaseBrowser::buildLeftTrim (QWidget *parent)
00312 {
00313     QWidget     *result = new QWidget (parent);
00314     result->setFixedWidth (0);
00315     
00316     return result;
00317 }
00318 
00319 QWidget *
00320 Ig3DBaseBrowser::buildBottomTrim (QWidget *parent)
00321 {
00322     QWidget     *result = new QWidget (parent);
00323     result->setFixedHeight (0);
00324     
00325     return result;
00326 }
00327 
00328 QWidget *
00329 Ig3DBaseBrowser::buildRightTrim (QWidget *parent)
00330 {
00331     QWidget     *result = new QWidget (parent);
00332     result->setFixedWidth (0);
00333     
00334     return result;
00335 }
00336 
00337 
00338 Ig3DBaseBrowser::~Ig3DBaseBrowser (void)
00339 {
00340     // FIXME: remove model selection, picking callbacks?
00341     IgSelectionService::get (m_state)
00342         ->remove (lat::CreateCallback (this, &Ig3DBaseBrowser::selectMessage));
00343     m_model->unlisten (Ig3DBaseModel::ModelChanged,
00344                        lat::CreateCallback (this, &Ig3DBaseBrowser::modelChanged));
00345 }
00346 
00347 IgState *
00348 Ig3DBaseBrowser::state (void) const
00349 { return m_state; }
00350 
00351 Ig3DBaseModel *
00352 Ig3DBaseBrowser::model (void) const
00353 { return m_model; }
00354 
00355 void
00356 Ig3DBaseBrowser::setAutoClipping (SbBool enable)
00357 {
00358     SoQtViewer::setAutoClipping (enable);
00359     if (enable)
00360     {
00361         SoCamera *camera = this->getCamera ();
00362         camera->farDistance.touch ();
00363         camera->nearDistance.touch ();
00364     }
00365 }
00366 
00367 void
00368 Ig3DBaseBrowser::setFeedbackVisibility (bool enable)
00369 {
00370     bool old = isFeedbackVisible ();
00371     if (enable != old)
00372         SoQtExaminerViewer::setFeedbackVisibility (enable);
00373 }
00374 
00375 void
00376 Ig3DBaseBrowser::setGridVisibility (bool enable)
00377 {     
00378     Ig3DBaseBrowser::drawGrid (enable);
00379 }
00380 
00381 bool
00382 Ig3DBaseBrowser::isGridVisible (void)
00383 {
00384     return m_grid;
00385 }
00386 
00387 void
00388 Ig3DBaseBrowser::drawGrid (const bool enable) 
00389 {
00390     // find the grid planes group
00391     SoNode* grid = findGroup (model ()->attachPoint (), Ig3DBaseModel::encode ("Grid Planes").getString ());
00392     SoGroup* all = 0;
00393         
00394     if (grid)
00395     {
00396         // and now find the group which contains all planes
00397         all = dynamic_cast<SoGroup *> (findGroup (grid, Ig3DBaseModel::encode ("All").getString ()));
00398     }
00399         
00400     if (all)
00401     {
00402         unsigned nbrChildren = all->getNumChildren ();
00403         IgSoGridPlane* plane = 0;
00404                 
00405         // iterate over all planes and enable or disable them
00406         for (unsigned i = 0; i < nbrChildren; i++)
00407         {
00408             plane = dynamic_cast<IgSoGridPlane* > (all->getChild (i));
00409             if (plane)
00410             {
00411                 plane->on = enable;
00412             }
00413         }
00414     }
00415     m_grid = enable;
00416 }
00417 
00418 void
00419 Ig3DBaseBrowser::zoomIn (void) 
00420 {    
00421     // There is no particular meaning in this 
00422     // number 0.5. It just looks like a reasonable step. 
00423     zoom (-0.5f);
00424 }
00425 
00426 void
00427 Ig3DBaseBrowser::zoomOut (void) 
00428 {    
00429     // There is no particular meaning in this 
00430     // number 0.5. It just looks like a reasonable step. 
00431     zoom (0.5f);
00432 }
00433 
00434 void
00435 Ig3DBaseBrowser::zoom (const float diffvalue)
00436 {
00437     SoCamera *cam = this->getCamera ();
00438     if (cam == NULL) return; // can happen for empty scenegraph
00439     SoType t = cam->getTypeId ();
00440 
00441     // This will be in the range of <0, ->>.
00442     float multiplicator = exp (diffvalue);
00443 
00444     if (t.isDerivedFrom (SoOrthographicCamera::getClassTypeId ())) 
00445     {
00446         // Since there's no perspective, "zooming" in the original sense
00447         // of the word won't have any visible effect. So we just increase
00448         // or decrease the field-of-view values of the camera instead, to
00449         // "shrink" the projection size of the model / scene.
00450         SoOrthographicCamera *oc = (SoOrthographicCamera *) cam;
00451         oc->height = oc->height.getValue () * multiplicator;
00452     }
00453     else if (t.isDerivedFrom (SoPerspectiveCamera::getClassTypeId ())) 
00454     {
00455         float oldfocaldist = cam->focalDistance.getValue ();
00456         cam->focalDistance = oldfocaldist * multiplicator;
00457 
00458         SbVec3f direction;
00459         cam->orientation.getValue ().multVec (SbVec3f (0, 0, -1), direction);
00460         cam->position = cam->position.getValue () +
00461                         (cam->focalDistance.getValue () - oldfocaldist) * -direction;
00462 
00463     }
00464     else 
00465     {
00466         static SbBool first = TRUE;
00467         if (first) 
00468         {
00469             SoDebugError::postWarning("Ig3DBaseBrowser::zoom",
00470                                       "unknown camera type, "
00471                                       "attempts to zoom will have no effect");
00472             first = FALSE;
00473         }
00474     }
00475 }
00476 
00477 void
00478 Ig3DBaseBrowser::toggleCameraType (void)
00479 {
00480     SoQtExaminerViewer::toggleCameraType ();
00481     SoCamera * const camera = this->getCamera ();
00482     camera->farDistance  = SHRT_MAX;
00483     camera->nearDistance  = 0.1;
00484     m_farDistanceSensor->attach (&camera->farDistance);
00485     m_nearDistanceSensor->attach (&camera->nearDistance);
00486     cameraToggled();
00487 }
00488 
00489 void
00490 Ig3DBaseBrowser::invertCamera (void)
00491 {
00492     SoCamera * const camera = this->getCamera ();
00493     if (!camera) return; // probably a scene-less viewer
00494 
00495     camera->position = camera->position.getValue () * -1.0F;
00496     camera->orientation.setValue (
00497         SbRotation (SbVec3f (0.F,-1.F,0.F), M_PI)
00498         * camera->orientation.getValue ());
00499 }
00500 
00501 void
00502 Ig3DBaseBrowser::farDistanceSensorCB (void *me, SoSensor *)
00503 {
00504     Ig3DBaseBrowser *self = static_cast<Ig3DBaseBrowser *> (me);
00505     if (self->isAutoClipping ())
00506     {
00507         SoCamera * const camera = self->getCamera ();
00508         self->m_farDistanceSensor->detach ();
00509         camera->farDistance  = SHRT_MAX;
00510         self->m_farDistanceSensor->attach (&camera->farDistance);
00511     }
00512 }
00513 
00514 void
00515 Ig3DBaseBrowser::nearDistanceSensorCB (void *me, SoSensor *)
00516 {
00517     Ig3DBaseBrowser *self = static_cast<Ig3DBaseBrowser *> (me);
00518     if (self->isAutoClipping ())
00519     {
00520         SoCamera * const camera = self->getCamera ();
00521         self->m_nearDistanceSensor->detach ();
00522         camera->nearDistance  = 0.1;
00523         self->m_nearDistanceSensor->attach (&camera->nearDistance);
00524     }
00525 }
00526 
00527 void
00528 Ig3DBaseBrowser::browse (IgRepresentable *object)
00529 {
00530     // FIXME: can we just depend on model change event?
00531     IgRep *rep = IgRepSet::lookup (object, m_model, true);
00532 
00533     // FIXME: terrible kludge; need something more robust...
00534     if (rep && m_first_time)
00535     {
00536         m_first_time = false;
00537         viewAll ();
00538     }
00539 
00540     // FIXME: select?
00541 }
00542 
00543 void
00544 Ig3DBaseBrowser::select (Ig3DBaseRep *rep)
00545 {
00546     // FIXME: handle multiple selection?
00547     if (m_selection != rep)
00548     {
00549         m_selection = rep;
00550 
00551         LOG(0, trace, LF3dbrowser, "changing selection to " << rep << '\n');
00552         ASSERT(m_model->sceneGraph()->isOfType(SoSelection::getClassTypeId()));
00553         SoSelection     *top = static_cast<SoSelection *>
00554                                (m_model->sceneGraph ());
00555         SoNode          *node = rep;
00556         SoPathList      *selected = const_cast<SoPathList *> (top->getList ());
00557         bool            alreadySelected = false;
00558         int             path = 0;
00559 
00560         LOG(0, trace, LF3dbrowser, " -- looping over selected items\n");
00561         // Check if the selected rep corresponds to an unselected node
00562         while (node && ! alreadySelected && path < selected->getLength ())
00563             alreadySelected = (*selected) [path++]->containsNode (node);
00564 
00565         if (! node)
00566             top->deselectAll ();
00567         else if (! alreadySelected)
00568         {
00569             // Find a path from the selection node to the selected node
00570             SoSearchAction finder;
00571             finder.setNode (node);
00572             finder.setFind (SoSearchAction::NODE);
00573             finder.apply (top);
00574 
00575             if (finder.getPath ())
00576             {
00577                 LOG(0, trace, LF3dbrowser, " -- selecting object\n");
00578 
00579                 // Set the node as selected.  Selection callbacks will
00580                 // fire on exit, which will result in a message on the
00581                 // bus.  `select' ignores the current selection policy
00582                 // so clear that manually.
00583                 LOG(0, trace, LF3dbrowser, " -- firing callback\n");
00584                 top->deselectAll ();
00585                 top->select (finder.getPath ());
00586             }
00587         }
00588     }
00589 }
00590 
00591 Ig3DBaseRep *
00592 Ig3DBaseBrowser::getCurrentPick (void) const
00593 {
00594     return m_currentPick;
00595 }
00596 
00597 Ig3DBaseRep *
00598 Ig3DBaseBrowser::getSelection (void) const
00599 {
00600     return m_selection;
00601 }
00602 
00603 void
00604 Ig3DBaseBrowser::setCurrentPick (Ig3DBaseRep *rep)
00605 {
00606     // NB: do not fire any notifications; this method is an internal
00607     // means to change a state without getting into loops.
00608     m_selection = rep;
00609     // FIXME: tell the rep (w/detailed path + point information)?
00610     // FIXME: how can we pass that extra detail in the selection?
00611 }
00612 
00613 const SoPickedPoint *
00614 Ig3DBaseBrowser::getCurrentPickPoint (void) const
00615 {
00616     return m_pick;
00617 }
00618 
00619 void
00620 Ig3DBaseBrowser::setCurrentPickPoint (const SoPickedPoint *pick)
00621 {
00622     // FIXME: validity time?
00623     m_pick = pick;
00624 }
00625 
00627 SoPath *
00628 Ig3DBaseBrowser::onPick (void *cb, const SoPickedPoint *pick)
00629 {
00630     // FIXME: pass pick to the 3d rep to allow it to give more detail
00631     Ig3DBaseBrowser *self = static_cast<Ig3DBaseBrowser *> (cb);
00632     //if (self->isWhatsThisPicking ()) return 0;
00633 
00634     self->setCurrentPickPoint (pick);
00635 
00636     // Find a matching rep for the selected node
00637     SoPath      *selection = pick->getPath ();
00638     const int   length = selection->getLength ();
00639     int         index = 0;
00640     Ig3DBaseRep *match = 0;
00641     for ( ; index < length; ++index)
00642     {
00643         // skip until we find a representation boundary
00644         SoNode  *node = selection->getNodeFromTail (index);
00645         LOG(0, trace, LF3dbrowser, "pick node [-" << index << "] = "
00646             << node->getName ().getString () << '\n');
00647 
00648         if ((match = Ig3DBaseRep::asRep (node)))
00649             break;
00650     }
00651 
00652     // select if matched and not already selected; otherwise deselect
00653     LOG(0, trace, LF3dbrowser, "pick --> " << index << " of " << length);
00654     if (index < length && self->getSelection () != match)
00655     {
00656         LOG(0, trace, LF3dbrowser, ": match and different from previous\n");
00657         return selection->copy (0, length - index);
00658     }
00659     else
00660     {
00661         LOG(0, trace, LF3dbrowser, ": no match or same as previously\n");
00662         return 0;
00663     }
00664 }
00665 
00666 void
00667 Ig3DBaseBrowser::onSelect (void *cb, SoPath *selection)
00668 {
00669     // FIXME: if 3d rep set more detail on pick, use it here
00670     // FIXME: handle multiple selection?
00671     ASSERT (selection);
00672     ASSERT (selection->getLength () > 0);
00673 
00674     LOG(0, trace, LF3dbrowser, "select: " << selection->getLength () << '\n');
00675     Ig3DBaseBrowser *self = static_cast<Ig3DBaseBrowser *> (cb);
00676     Ig3DBaseRep *match = Ig3DBaseRep::asRep (selection->getNodeFromTail (0));
00677     ASSERT (match);
00678 
00679     self->setCurrentPick (match);
00680     IgSelectionService::get (self->m_state)
00681         ->broadcast (IgSelectionMessage (match->context ()));
00682 }
00683 
00684 void
00685 Ig3DBaseBrowser::onDeselect (void *cb, SoPath *selection)
00686 {
00687     // FIXME: handle multiple selection?
00688     LOG(0, trace, LF3dbrowser, "deselect: " << selection->getLength () << '\n');
00689     Ig3DBaseBrowser *self = static_cast<Ig3DBaseBrowser *> (cb);
00690     Ig3DBaseRep *match = Ig3DBaseRep::asRep (selection->getNodeFromTail (0));
00691     ASSERT (match);
00692     self->setCurrentPick (0);
00693     IgSelectionService::get (self->m_state)
00694         ->broadcast (IgSelectionMessage (0));
00695 }
00696 
00698 void
00699 Ig3DBaseBrowser::selectMessage (IgSelectionMessage message)
00700 {
00701     if (! message.context ())
00702         select (0);
00703     else if (Ig3DBaseRep *rep = dynamic_cast<Ig3DBaseRep *>
00704              (IgRepSet::lookup (message.context (), m_model, true)))
00705         select (rep);
00706 }
00707 
00709 void
00710 Ig3DBaseBrowser::modelChanged (Ig3DBaseModelEvent)
00711 {
00712     getSceneManager ()->scheduleRedraw ();
00713 }
00714 
00715 
00717 void
00718 Ig3DBaseBrowser::save (void)
00719 { saveNode (m_model->sceneGraph (), "Save Scene As...", getShellWidget ()); }
00720 
00721 void
00722 Ig3DBaseBrowser::print (void)
00723 {
00724     QString     vector2EPS ("Vector EPS [Level 2] (*.eps)");
00725     QString     vector3EPS ("Vector EPS [Level 3] (*.eps)");
00726     QString     vectorPDF  ("Portable Document Format (*.pdf)");
00727     QStringList filters (vector2EPS);
00728     filters.append (vector3EPS);
00729     filters.append (vectorPDF);
00730     
00731     SoOffscreenRenderer *renderer =
00732         new SoOffscreenRenderer (this->getViewportRegion ());
00733     
00734     int num =renderer->getNumWriteFiletypes();
00735 
00736     if (num == 0)
00737     {
00738         filters.append ("Encapsulated postscript (*.eps)");
00739         filters.append ("Encapsulated postscript (*.ps)");
00740         filters.append ("The SGI RGB file format (*.rgb)");
00741         filters.append ("The SGI RGB file format (*.rgba)");
00742         filters.append ("The SGI RGB file format (*.bw)");
00743         filters.append ("The SGI RGB file format (*.inta)");
00744         filters.append ("The SGI RGB file format (*.int)");
00745     }
00746     else
00747     {
00748         for (int i=0; i < num; i++)
00749         {
00750             SbPList extlist;
00751             SbString fullname, description;
00752             renderer->getWriteFiletypeInfo(i, extlist, fullname, description);
00753             QString filter (fullname.getString());
00754             filter+=" (*.";
00755             for (int j=0; j < extlist.getLength(); j++)
00756                 filters.append (filter+(const char*)extlist[j]+")");
00757         }
00758     }
00759     delete renderer;
00760 
00761     // Pop up file dialog to as for the name.
00762     QFileDialog dialog (getShellWidget (), "Print To File", true);
00763     dialog.setFilters (filters);
00764     dialog.setMode (QFileDialog::AnyFile);
00765     bool tryagain = true;
00766     QString     f;
00767     while (tryagain)
00768     {
00769         if (dialog.exec () != QDialog::Accepted)
00770             return;
00771 
00772         f = dialog.selectedFile ();
00773         if (f.isEmpty ())
00774             return;
00775         else
00776         {
00777             lat::Filename sealf (f.latin1());
00778             QString dir (sealf.directory().name());
00779             if (sealf.exists ())
00780             {
00781                 LOG(0, trace, LF3dbrowser, QString(f+": File already exists.\n").latin1());
00782                 int button = QMessageBox::warning (getShellWidget (), "File already exists",
00783                                                    "File \""+f+"\" already exists.\n"
00784                                                    "Do you want to overwrite it?",
00785                                                    "Yes", "No");
00786                 if (button == 0)
00787                 {
00788                     if (!sealf.isWritable ())
00789                     {
00790                         LOG(0, trace, LF3dbrowser, QString(f+": File not write able.\n").latin1());
00791                         int button = QMessageBox::warning (getShellWidget (), "Access denied",
00792                                                            "File \""+f+"\" not write able.\n"
00793                                                            "Do you want to select some other file?",
00794                                                            "Yes", "No");
00795                         if (button == 1)
00796                             return;
00797                     }
00798                     else
00799                         tryagain = false;
00800                 }
00801             }
00802             else if (!lat::Filename(dir.latin1()).isWritable ())
00803             {
00804                 LOG(0, trace, LF3dbrowser, QString(dir+": Directory not write able.\n").latin1());
00805                 int button = QMessageBox::warning (getShellWidget (), "Access denied",
00806                                                    "You do not have permissions to write in \""+dir+"\" directory.\n"
00807                                                    "Do you want to select some other file?",
00808                                                    "Yes", "No");
00809                 if (button == 1)
00810                     return;
00811             }
00812             else
00813                 tryagain = false;
00814         }
00815     }
00816     // Pick format settings.
00817     float       ppi = SoOffscreenRenderer::getScreenPixelsPerInch ();
00818     //float     dpi = 300.;
00819     float       dpi = ppi;
00820     QString     format ("jpg");
00821 
00822     QString sfilter = dialog.selectedFilter ();
00823     int extIndexStart = sfilter.findRev(".")+1;
00824     int extIndexEnd = sfilter.findRev(")");
00825     format = sfilter.mid (extIndexStart, extIndexEnd-extIndexStart);
00826     
00827     // Add suffix.
00828     QString suffix ("." + format);
00829     if (f.find (suffix, -(format.length()+1)) == -1)
00830         f += suffix;
00831 
00832     // FIXME: Use a state element to remeber all file operations(save, open)
00833     QDir::setCurrent (QFileInfo (f).dirPath ());
00834     
00835     QApplication::setOverrideCursor (Qt::waitCursor);
00836     if (sfilter == vector2EPS)
00837         printVector (f, format, 2);
00838     else if (sfilter == vector3EPS)
00839         printVector (f, format, 3);
00840     else if (sfilter == vectorPDF)
00841         printVector (f, format, 0);
00842     else
00843         printBitmap (f, ppi, dpi, format);
00844     QApplication::restoreOverrideCursor ();
00845 }
00846 
00848 void
00849 Ig3DBaseBrowser::printBitmap (QString file, float ppi,
00850                               float dpi, QString format)
00851 {
00852     // This is mostly like the *Inventor Mentor* example.
00853     // Initialise off-screen renderer.
00854     float               r, g, b;
00855     SbViewportRegion    outvr = this->getViewportRegion ();
00856     
00857     SbVec2s             pixels (outvr.getViewportSizePixels ());
00858     SbVec2s             size ((short) (pixels [0] * dpi / ppi + 0.5), (short) (pixels [1] * dpi / ppi + 0.5));
00859     SbVec2s             origin = outvr.getViewportOriginPixels();
00860     outvr.setViewportPixels (origin, size);
00861 
00862     // Set up a custom GL render action for the offscreen rendered.
00863     // Do *not* use the one returned by `getGLRenderAction()': doing
00864     // so leaves the display in a confused state and doesn't produce
00865     // an output file.  This way we also avoid issues with having to
00866     // mess and then later reset antialiasing and related parameters.
00867     SoGLRenderAction    *ra = new SoGLRenderAction (outvr);
00868     SoOffscreenRenderer *renderer = new SoOffscreenRenderer (outvr);
00869 
00870     // FIXME? renderer.setComponents (SoOffscreenRenderer::RGB_TRANSPARENCY);
00871     getSceneManager ()->getBackgroundColor ().getValue (r, g, b);
00872     renderer->setBackgroundColor (SbColor (r, g, b));
00873     renderer->setGLRenderAction (ra);
00874     ra->setTransparencyType (SoGLRenderAction::SORTED_OBJECT_BLEND);
00875     ra->setSmoothing (TRUE);
00876     ra->setNumPasses (8);
00877 
00878     // Want to render from above the SceneGraph so we get what the
00879     // camera sees; SoQtViewer uses the following code.  (FIXME:
00880     // do we actually want to just render root, or look for camera?)
00881     SoNode *root = getSceneManager ()->getSceneGraph ();
00882 
00883     SbBool ok = renderer->render (root);
00884     if (!ok) 
00885     {
00886         QMessageBox::information (0, "IGUANA Print Info",
00887                                   tr ("Printing of the %1 format works only\n"
00888                                       "if you run locally installed software\n"
00889                                       "If iguana is running remotely, please,\n"
00890                                       "print as vector Postscript.").arg (file.right (3)));
00891     }
00892     else if (!renderer->writeToFile (file.latin1 (), format.latin1 ()))
00893     {
00894         LOG(0, trace, LF3dbrowser, 
00895             QString(file + ": Failed to open file for writing.\n").latin1());
00896         QMessageBox::warning (getShellWidget (), "System Error",
00897                               "Failed to open file \""+file+"\" for writing.",
00898                               "Ok");
00899     }
00900     delete renderer;
00901     delete ra;
00902 }
00903 
00904 void
00905 Ig3DBaseBrowser::printVector (QString file, QString format, int level)
00906 {
00907     // Use gl2ps to print vector graphics output.  To be extended to
00908     // handle other vector graphics formats (SVG, WMF).
00909     static IgSoGL2PSAction  *gl2psAction = 0;
00910     if (FILE *output = fopen (file.utf8 (), "wb+"))
00911     {
00912         int type = GL2PS_EPS;
00913         if (format == "pdf")
00914             type = GL2PS_PDF;
00915         else if (format == "eps")
00916             type = GL2PS_EPS;
00917         else
00918             ASSERT (0);
00919         
00920         if (! gl2psAction )
00921             gl2psAction = new IgSoGL2PSAction (this->getViewportRegion ());
00922                         
00923         gl2psAction->setViewportRegion (this->getViewportRegion ());
00924         SoGLRenderAction* prevAction = getGLRenderAction ();
00925         setGLRenderAction (gl2psAction);
00926                 
00927         int state = GL2PS_OVERFLOW;
00928         while (state == GL2PS_OVERFLOW)
00929         { 
00930             int gl2psOptions = GL2PS_SILENT | GL2PS_USE_CURRENT_VIEWPORT
00931                                | (level < 3 ? GL2PS_NO_PS3_SHADING : 0)
00932                                | getGL2PSOptions ();
00933             gl2psBeginPage ("IGUANA Scene Graph", "IGUANA", NULL,
00934                             type, GL2PS_BSP_SORT,
00935                             gl2psOptions,
00936                             GL_RGBA, 0, NULL,0, 0, 0,
00937                             m_gl2psFBBufferSize, output, NULL);
00938             actualRedraw ();
00939             state = gl2psEndPage();
00940             if (state == GL2PS_OVERFLOW)
00941                 m_gl2psFBBufferSize += 1024*1024;
00942         }
00943         fclose (output);
00944         setGLRenderAction (prevAction);
00945     }
00946     else
00947     {
00948         LOG(0, trace, LF3dbrowser, QString(file +": Failed to open file for writing.\n").latin1());
00949         QMessageBox::warning (getShellWidget (), "System Error",
00950                               "Failed to open file \""+file+"\" for writing.",
00951                               "Ok");
00952     }
00953 }
00954 
00955 int
00956 Ig3DBaseBrowser::getGL2PSOptions (void)
00957 { return m_gl2psOptions; }
00958 
00959 void
00960 Ig3DBaseBrowser::setGL2PSOptions (int options)
00961 { m_gl2psOptions = options; }
00962 
00964 void
00965 Ig3DBaseBrowser::repMenu (IgQtObjectMenuMessage message)
00966 {
00967     static const IgQtObjectMenu::ItemDef defs [] = {
00968         { -1, MENU_3D_OPS, 0, 0, -1 },
00969         { -1, MENU_SEEKTO, "Seek To", SLOT(repSeekTo()), -1 },
00970     };
00971     static const int    ndefs = sizeof (defs)/sizeof (defs [0]);
00972     IgRepresentable     *object = message.object ();
00973 
00974     m_menuRep = dynamic_cast<Ig3DBaseRep *>
00975                 (IgRepSet::lookup (object, m_model, false));
00976 
00977     message.menu ()->removeFromDefs (defs, ndefs);
00978     if (m_menuRep)
00979         // Add our items if they aren't there yet.
00980         message.menu ()->insertFromDefs (this, defs, ndefs);
00981         
00982     /*    if (! m_menuRep)
00983     // An irrelevant object, remove our items.
00984     message.menu ()->removeFromDefs (defs, ndefs);
00985     else 
00986     // Add our items if they aren't there yet.
00987     message.menu ()->insertFromDefs (this, defs, ndefs);
00988     */
00989 }
00990 
00991 void
00992 Ig3DBaseBrowser::repSeekTo (void)
00993 {
00994     ASSERT (m_menuRep);
00995 
00996     // Locate the center point of the object
00997     SoGetBoundingBoxAction      bbaction (getViewportRegion ());
00998     SoSearchAction              search;
00999     search.setNode (m_menuRep);
01000     search.apply (m_model->sceneGraph ());
01001     ASSERT (search.getPath ());
01002     bbaction.apply (search.getPath ());
01003 
01004     // Compute various points and directions; find a rotation that puts
01005     // the current camera direction into a new one
01006     SoCamera    *camera = getCamera ();
01007     SbBox3f     bbox = bbaction.getBoundingBox ();
01008     SbVec3f     hitpoint = bbox.getCenter ();
01009     SbVec3f     here = camera->position.getValue ();
01010     SbVec3f     dir = hitpoint - here;
01011     SbVec3f     olddir;
01012     float       fd = (bbox.getMin () - bbox.getMax ()).length () / 2;
01013 
01014     dir.normalize ();
01015 
01016     camera->orientation.getValue ().multVec (SbVec3f (0, 0, -1), olddir);
01017     SbRotation  diffrot (olddir, dir);
01018 
01019     // Move the camera
01020     camera->focalDistance = fd;
01021     camera->orientation.setValue (camera->orientation.getValue () * diffrot);
01022     camera->position.setValue (hitpoint - fd * dir);
01023 }
01024 
01025 void
01026 Ig3DBaseBrowser::leftWheelPressed (void)
01027 { leftWheelStart (); }
01028 
01029 void
01030 Ig3DBaseBrowser::leftWheelChanged (float by)
01031 { leftWheelMotion (by); }
01032 
01033 void
01034 Ig3DBaseBrowser::leftWheelReleased (void)
01035 { leftWheelFinish (); }
01036 
01037 
01038 
01039 Ig3DBaseRep *
01040 Ig3DBaseBrowser::menuRep (void)
01041 { return m_menuRep; }
01042 
01043 void
01044 Ig3DBaseBrowser::resetToHomePosition (void)
01045 {
01046     SoQtViewer::resetToHomePosition ();    
01047 }
01048 
01049 void
01050 Ig3DBaseBrowser::saveHomePosition (void)
01051 {
01052     SoQtViewer::saveHomePosition ();    
01053 }
01054 
01055 void
01056 Ig3DBaseBrowser::viewAll (void)
01057 {
01058     SoQtViewer::viewAll ();
01059 }
01060 
01061 void
01062 Ig3DBaseBrowser::seek (void)
01063 {
01064     if (SoQtViewer::isSeekMode())
01065     {
01066         SoQtViewer::setSeekMode (false);
01067         setComponentCursor (SoQtCursor::getRotateCursor ());
01068     }
01069     else
01070     {
01071         SoQtViewer::setSeekMode (true);
01072         if (isAnimating ()) { stopAnimating (); }
01073         setComponentCursor(SoQtCursor(SoQtCursor::CROSSHAIR));
01074     }
01075 }
01076 
01077 void
01078 Ig3DBaseBrowser::view (void)
01079 {
01080     if (isViewing () != true)
01081     {
01082         m_whatsThisPicking = false;
01083         SoQtViewer::setViewing (true);    
01084         setComponentCursor (SoQtCursor::getRotateCursor ());    
01085     }
01086 }
01087 
01088 void
01089 Ig3DBaseBrowser::pick (void)
01090 {
01091     if (isViewing () != false)
01092     {
01093         SoQtViewer::setViewing (false);    
01094         SoQtViewer::setSeekMode (false);
01095         setComponentCursor(SoQtCursor(SoQtCursor::DEFAULT));
01096     }    
01097 }
01098 
01099 void
01100 Ig3DBaseBrowser::autoPrint (void)
01101 {    
01102     autoPrint (this->getTitle ());
01103 }
01104 
01105 void
01106 Ig3DBaseBrowser::autoPrint (const std::string text)
01107 {
01108     QDateTime dt = QDateTime::currentDateTime ();
01109     QString fName = "screenShot-" + dt.toString ("hh:mm:ss.zzz-dd.MM.yyyy") + ".png";
01110     QString dName = "screenShot-" + dt.toString ("hh:mm:ss.zzz-dd.MM.yyyy") + ".date";
01111         
01112     SbColor c = getBackgroundColor ();
01113     SoOffscreenRenderer osr (this->getViewportRegion ());
01114     osr.setBackgroundColor (c);
01115     SoNode *root = getSceneManager ()->getSceneGraph ();
01116     SbBool ok = osr.render (root);
01117         
01118     if (!ok) { return; }
01119     // ok = osr.writeToRGB (fName);
01120     ok = osr.writeToFile (fName.latin1 (), "png");
01121     if (!ok) { return; }
01122         
01123     dt = QDateTime::currentDateTime ();
01124     QFile file (dName);
01125     if  (file.open (IO_WriteOnly)) 
01126     {
01127         QTextStream stream (&file);
01128         stream << dt.toString ("ddd MMM d hh:mm:ss.zzz yyyy") << "\n";
01129         stream << text << "\n";
01130         file.close ();
01131     }
01132 }
01133 
01134 void
01135 Ig3DBaseBrowser::viewPlaneX (void) 
01136 {
01137     SoCamera * const camera = this->getCamera ();
01138     if (!camera) return; // probably a scene-less viewer
01139         
01140     camera->position = SbVec3f(-1,0,0) * camera->position.getValue().length();
01141     camera->orientation = SbRotation(SbVec3f(0,1,0),-M_PI/2.f);
01142 }
01143 
01144 void
01145 Ig3DBaseBrowser::viewPlaneY (void)
01146 {
01147     SoCamera * const camera = this->getCamera ();
01148     if (!camera) return; // probably a scene-less viewer
01149         
01150     SbVec3f norient = SbVec3f(0,-1,0);
01151     camera->position = -norient * camera->position.getValue().length();
01152     camera->orientation = SbRotation(SbVec3f(0,0,1),-M_PI/2.f) * 
01153                           SbRotation(SbVec3f(0,0,-1),norient);
01154 }
01155 
01156 void
01157 Ig3DBaseBrowser::viewPlaneZ (void) 
01158 {
01159     SoCamera * const camera = this->getCamera ();
01160     if (!camera) return; // probably a scene-less viewer
01161         
01162     camera->position = SbVec3f(0,0,1) * camera->position.getValue().length();
01163     camera->orientation = SbRotation::identity();
01164 }
01165 
01166 bool
01167 Ig3DBaseBrowser::saveNode (SoNode *node, const QString& title,
01168                            QWidget* parent /* = 0 */, const char* file /*= 0*/)
01169 {
01170     QString f = "";
01171     bool binaryfile = false;
01172         
01173     if (file == 0)
01174     {
01175         QFileDialog     dialog (QString::null, QString::null, parent,
01176                                 title, true);
01177         QString binary ("Binary OIV Files (*.iv)");
01178         QString ascii  ("ASCII OIV Files (*.iv)");
01179         QStringList     filters (ascii);
01180         filters.append (binary);
01181         dialog.setFilters (filters);
01182         dialog.setMode (QFileDialog::AnyFile);
01183         
01184         bool tryagain = true;
01185         while (tryagain)
01186         {
01187             if (dialog.exec () != QDialog::Accepted)
01188                 return false;
01189         
01190             f = dialog.selectedFile ();
01191             if (f.isEmpty ())
01192                 return false;
01193             else
01194             {
01195                 lat::Filename sealf (f.latin1());
01196                 if (sealf.exists ())
01197                 {
01198                     int button = QMessageBox::warning (parent, "File already exists",
01199                                                        "File \""+f+"\" already exists.\n"
01200                                                        "Do you want to overwrite it?",
01201                                                        "Yes", "No");
01202                     if (button == 0)
01203                     {
01204                         if (!sealf.isWritable ())
01205                         {
01206                             int button = QMessageBox::warning (parent, "Access denied",
01207                                                                "File \""+f+"\" not write able.\n"
01208                                                                "Do you want to select some other file?",
01209                                                                "Yes", "No");
01210                             if (button == 1)
01211                                 return false;
01212                         }
01213                         else
01214                             tryagain = false;
01215                     }
01216                 }
01217                 else if (!lat::Filename(dialog.dirPath ().latin1()).isWritable ())
01218                 {
01219                     int button = QMessageBox::warning (parent, "Access denied",
01220                                                        "You do not have permissions to write in \""+dialog.dirPath ()+"\" directory.\n"
01221                                                        "Do you want to select some other file?",
01222                                                        "Yes", "No");
01223                     if (button == 1)
01224                         return false;
01225                 }
01226                 else
01227                     tryagain = false;
01228             }
01229         }
01230         if (dialog.selectedFilter () == binary)
01231             binaryfile = true;
01232     }
01233     else
01234         f = file;
01235         
01236     if (! (f.length () > 3 && f.find (".iv", -3) != -1))
01237         f += ".iv";
01238         
01239     QDir::setCurrent (QFileInfo (f).dirPath ());
01240     return writeNode (node, f.utf8 (), binaryfile);
01241 }
01242 
01243 bool
01244 Ig3DBaseBrowser::writeNode (SoNode *node, const QString& file, bool binary,
01245                             QWidget* parent /* = 0 */)
01246 {
01247     SoOutput out;
01248     QApplication::setOverrideCursor (Qt::waitCursor);
01249     bool ret = false;
01250     if (out.openFile (file.utf8 ()))
01251     {
01252         out.setBinary (binary);
01253         SoWriteAction writer (&out);
01254         writer.apply (node);
01255         ret = true;
01256     }
01257     else
01258     {
01259         QMessageBox::warning (parent, "System Error",
01260                               "Failed to open file \""+file+"\" for writing."
01261                               "Ok");
01262     }
01263     QApplication::restoreOverrideCursor ();
01264     return ret;
01265 }
01266 
01267 SoNode*
01268 Ig3DBaseBrowser::openNode (const QString& nodeName, const QString& title,
01269                            QWidget* parent /* = 0 */, const char* file /*= 0*/)
01270 {
01271     // note:
01272     // SoDB::read (&file, node) [sometimes] has a buggy behaviour when 
01273     // loading *.iv files. Some parts of the scene graph might get copied 
01274     // because of a still unknown reason. For example when tried to save a
01275     // "grid planes" graph, the grid plane would get a "shadow" grid.
01276 
01277     QString filename = "";
01278     if (file != 0)
01279     {
01280         filename = file;
01281     }
01282     else
01283     {
01284         filename = 
01285             QFileDialog::getOpenFileName ("./",
01286                                           "Open Inventor files (*.iv)",
01287                                           0,
01288                                           QString::null,
01289                                           0,
01290                                           0,
01291                                           title);
01292     }
01293 
01294     if (filename != QString::null && !filename.isEmpty())
01295     {
01296         SoNode      *node = 0;
01297         SoInput     file;
01298         if (! file.openFile (filename.latin1 ()) 
01299             || ! SoDB::read (&file, node) 
01300             || ! node)
01301         {
01302             QMessageBox::warning (parent,
01303                                   "File Access Error", 
01304                                   "Can not open file \""+ filename + "\" for reading.", "Ok");
01305             return 0;
01306         }
01307         QDir::setCurrent (QFileInfo (filename).dirPath ());
01308                 
01309         if (nodeName.isEmpty ()) return node;
01310                 
01311         node = findGroup (node, nodeName.latin1 ());
01312                 
01313         if (!node)
01314             QMessageBox::warning (parent,
01315                                   "Wrong file", 
01316                                   "Can not find node \""+nodeName+"\" in file \""+ filename + "\".", "Ok");
01317         return node;
01318     }
01319     return 0;
01320 }
01321 
01322 SoNode*
01323 Ig3DBaseBrowser::findGroup (SoNode *node, const char* name)
01324 {
01325     if (node->isOfType(SoGroup::getClassTypeId()))
01326     {
01327         if (node->getName () == name)
01328             return node;
01329         else
01330         {
01331             SoGroup * group = dynamic_cast<SoGroup*>(node);
01332             int count = group->getNumChildren ();
01333             for (int i = 0; i < count; i++)
01334             {
01335                 SoNode *n = findGroup (group->getChild(i), name);
01336                 if (n) return n;
01337             }
01338         }
01339     }
01340     return 0;
01341 }
01342 
01343 bool
01344 Ig3DBaseBrowser::isWhatsThisPicking (void)
01345 { return m_whatsThisPicking; }
01346 
01347 void
01348 Ig3DBaseBrowser::setWhatsThisPicking (bool enable /* = true */)
01349 {
01350     if (m_whatsThisPicking != enable)
01351     {
01352         m_whatsThisPicking = enable;
01353         if (enable)
01354         {
01355             m_oldView = isViewing ();
01356             m_oldSeek = isSeekMode();
01357             pick ();
01358             getGLWidget ()->setCursor (QCursor (Qt::WhatsThisCursor));
01359         }
01360         else
01361         {
01362             if (m_oldView)
01363             {
01364                 view ();
01365                 if (m_oldSeek)
01366                     seek ();
01367             }
01368             else
01369             {
01370                 pick ();
01371                 setComponentCursor(SoQtCursor(SoQtCursor::DEFAULT));
01372             }
01373         }
01374     }
01375 }

Generated on Tue Jun 9 17:38:35 2009 for CMSSW by  doxygen 1.5.4