MainWindow.qt.C

00001 #ifndef MAINWINDOW_C
00002 #define MAINWINDOW_C
00003 
00004 #include "NeovisionII/NeoAnnotate/MainWindow.qt.H"
00005 #include "NeovisionII/NeoAnnotate/AnnotationObject.qt.H"
00006 #include "NeovisionII/NeoAnnotate/AnimationDelegate.qt.H"
00007 #include "NeovisionII/NeoAnnotate/AnnotationObjectMgrDelegate.qt.H"
00008 #include <Qt/QtXml>
00009 
00010 //######################################################################
00011 void MainWindow::createMenuBar()
00012 {
00013   QMenu * fileMenu = menuBar()->addMenu(tr("&File"));
00014 
00015 
00016   QAction * createDBEntryAction = fileMenu->addAction(tr("&New Annotation"));
00017   createDBEntryAction->setShortcut(tr("Ctrl+N"));
00018   connect(createDBEntryAction, SIGNAL(triggered()), this, SLOT(createDBEntry()));
00019 
00020   QAction * saveToDBAction      = fileMenu->addAction("&Save Annotation");
00021   saveToDBAction->setShortcut(tr("Ctrl+S"));
00022   connect(saveToDBAction,      SIGNAL(triggered()), this, SLOT(saveAnnotationToDB()));
00023 
00024   QAction * openFromDBAction      = fileMenu->addAction("&Open Existing Annotation");
00025   openFromDBAction->setShortcut(tr("Ctrl+O"));
00026   connect(openFromDBAction,    SIGNAL(triggered()), this, SLOT(openAnnotationFromDB()));
00027 
00028   QAction * preferencesAction   = fileMenu->addAction("Preferences...");
00029   connect(preferencesAction,    SIGNAL(triggered()), this, SLOT(openPrefsDialog()));
00030 
00031   QMenu * connectionMenu = menuBar()->addMenu(tr("&Connection"));
00032   
00033   QAction * connectToDBAction = connectionMenu->addAction("Connect To &Database");
00034   connect(connectToDBAction, SIGNAL(triggered()), &itsDBManager, SLOT(connectToDb()));
00035 
00036   QAction * chooseAnnotationSourceAction = connectionMenu->addAction("Choose Annotation &Source");
00037   connect(chooseAnnotationSourceAction, SIGNAL(triggered()), &itsDBManager, SLOT(chooseAnnotationSource()));
00038 }
00039 
00040 //######################################################################
00041 void MainWindow::createToolbar()
00042 {
00043   //Initialize all of the qaction buttons with appropriate icons and tooltips
00044   //Icons from http://www.visualpharm.com/
00045   QPushButton * zoomInAction    = new QPushButton(QIcon("src/NeovisionII/NeoAnnotate/icons/Zoom-In-icon.png"),"",  this);
00046   QPushButton * zoomOutAction   = new QPushButton(QIcon("src/NeovisionII/NeoAnnotate/icons/Zoom-Out-icon.png"),"", this);
00047   QPushButton * cursorAction    = new QPushButton(QIcon("src/NeovisionII/NeoAnnotate/icons/cursor-arrow.png"),"",  this);
00048   QPushButton * addVertexAction = new QPushButton(QIcon("src/NeovisionII/NeoAnnotate/icons/cursor-add.png"),"",    this); 
00049   QPushButton * remVertexAction = new QPushButton(QIcon("src/NeovisionII/NeoAnnotate/icons/cursor-rem.png"),"",    this);
00050   QPushButton * rotateAction    = new QPushButton(QIcon("src/NeovisionII/NeoAnnotate/icons/rotate-icon.jpg"),"",   this);
00051 
00052   zoomInAction->setToolTip("Zoom In");
00053   zoomOutAction->setToolTip("Zoom Out");
00054   cursorAction->setToolTip("Edit Objects");
00055   addVertexAction->setToolTip("Add Vertex");
00056   remVertexAction->setToolTip("Remove Vertex");
00057 
00058   zoomInAction->setIconSize(QSize(24,24));
00059   zoomOutAction->setIconSize(QSize(24,24));
00060   cursorAction->setIconSize(QSize(24,24));
00061   addVertexAction->setIconSize(QSize(24,24));
00062   remVertexAction->setIconSize(QSize(24,24));
00063 
00064   QButtonGroup * cursorGroup = new QButtonGroup(this);
00065   cursorGroup->addButton(cursorAction);
00066   cursorGroup->addButton(addVertexAction);
00067   cursorGroup->addButton(remVertexAction);
00068   cursorGroup->addButton(rotateAction);
00069 
00070   cursorAction->setCheckable(true);
00071   addVertexAction->setCheckable(true);
00072   remVertexAction->setCheckable(true);
00073   rotateAction->setCheckable(true);
00074 
00075   //Create the opacity slider mechanism
00076   QHBoxLayout * opacityLayout = new QHBoxLayout(this);
00077   QLabel  * opacityNameLbl  = new QLabel(this);
00078   QSlider * opacitySlider  = new QSlider(Qt::Horizontal, this);
00079   QLabel  * opacityAmtLbl   = new QLabel(this);
00080   QLabel  * opacityPerLbl   = new QLabel(this);
00081   connect(opacitySlider, SIGNAL(valueChanged(int)), opacityAmtLbl, SLOT(setNum(int)));
00082   connect(opacitySlider, SIGNAL(valueChanged(int)), itsObjectManager, SLOT(setOpacity(int)));
00083   opacitySlider->setValue(50);
00084   opacitySlider->setRange(0, 100);
00085   opacityNameLbl->setText("Opacity: ");
00086   opacityPerLbl->setText("%");
00087   opacityLayout->addWidget(opacityNameLbl);
00088   opacityLayout->addWidget(opacitySlider);
00089   opacityLayout->addWidget(opacityAmtLbl);
00090   opacityLayout->addWidget(opacityPerLbl);
00091   QGroupBox * opacityBox    = new QGroupBox(this);
00092   opacityBox->setMaximumWidth(200);
00093   opacityBox->setLayout(opacityLayout);
00094 
00095   //Create the toolbar
00096   QToolBar * toolbar = addToolBar(tr("Edit"));
00097 
00098   //Add all of the action buttons to the toolbar
00099   toolbar->addWidget(zoomInAction);
00100   toolbar->addWidget(zoomOutAction);
00101   toolbar->addSeparator();
00102   toolbar->addSeparator();
00103   toolbar->addWidget(cursorAction);
00104   toolbar->addWidget(addVertexAction);
00105   toolbar->addWidget(remVertexAction);
00106   toolbar->addWidget(rotateAction);
00107   toolbar->addSeparator();
00108   toolbar->addSeparator();
00109   toolbar->addWidget(opacityBox);
00110   toolbar->addSeparator();
00111 
00112   //Connect each action's triggered signal to the appropriate action
00113   connect(zoomInAction,    SIGNAL(clicked()), itsMainDisplay,  SLOT(zoomIn()));
00114   connect(zoomOutAction,   SIGNAL(clicked()), itsMainDisplay,  SLOT(zoomOut()));
00115   connect(cursorAction,    SIGNAL(clicked()), itsMainDisplay,  SLOT(setActionMode_Cursor()));
00116   connect(addVertexAction, SIGNAL(clicked()), itsMainDisplay,  SLOT(setActionMode_AddVertex()));
00117   connect(remVertexAction, SIGNAL(clicked()), itsMainDisplay,  SLOT(setActionMode_RemVertex()));
00118   connect(rotateAction,    SIGNAL(clicked()), itsMainDisplay,  SLOT(setActionMode_Rotate()));
00119 
00120   //Trigger the default cursor action
00121   cursorAction->click();
00122 }
00123 
00124 //######################################################################
00125 QWidget* MainWindow::createObjectList()
00126 {
00127   //Create a layout for the object list and associated controls
00128   QTableView *objectList = new QTableView;
00129   objectList->setSelectionBehavior(QAbstractItemView::SelectRows);
00130   objectList->setSelectionMode(QAbstractItemView::SingleSelection);
00131   objectList->setModel(itsObjectManager);
00132   QVBoxLayout *objectListLayout = new QVBoxLayout;
00133   objectListLayout->addWidget(objectList);
00134 
00135   AnnotationObjectMgrDelegate* objMgrDel = new AnnotationObjectMgrDelegate(this);
00136   objMgrDel->setObjCategories(itsDBManager.getObjCategories());
00137   objectList->setItemDelegate(objMgrDel);
00138 
00139   //When a user clicks on an object in the list, the manager should highlight it, etc.
00140   connect(objectList, SIGNAL(clicked(const QModelIndex &)), itsObjectManager, SLOT(select(const QModelIndex &)));
00141 
00142   //When the manager selects an object, the object list should highlight the appropriate row
00143   connect(itsObjectManager, SIGNAL(selectingObject(int)), objectList, SLOT(selectRow(int)));
00144 
00145   QHBoxLayout *objectButtonLayout = new QHBoxLayout;
00146 
00147   QPushButton *addObjectButton = new QPushButton(QIcon("src/NeovisionII/NeoAnnotate/icons/Add-icon.png"),"");
00148   QPushButton *delObjectButton = new QPushButton(QIcon("src/NeovisionII/NeoAnnotate/icons/Remove-icon.png"),"");
00149   connect(addObjectButton, SIGNAL(clicked()), this, SLOT(addObject()));
00150   connect(delObjectButton, SIGNAL(clicked()), itsObjectManager, SLOT(removeObject()));
00151 
00152   objectButtonLayout->addWidget(addObjectButton);
00153   objectButtonLayout->addWidget(delObjectButton);
00154   objectButtonLayout->addStretch();
00155 
00156   objectListLayout->addLayout(objectButtonLayout);
00157   QWidget *objectListWidget = new QWidget;
00158   objectListWidget->setLayout(objectListLayout);
00159 
00160   return objectListWidget;
00161 }
00162 
00163 //######################################################################
00164 QTableView* MainWindow::createAnimationControls()
00165 {
00166   itsAnimationView = new QTableView;
00167   itsAnimationView->setMouseTracking(true);
00168   itsAnimationView->setSelectionMode(QAbstractItemView::ExtendedSelection);
00169   itsAnimationView->setSelectionBehavior(QAbstractItemView::SelectItems);
00170   itsAnimationView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
00171   itsAnimationView->horizontalHeader()->setResizeMode(QHeaderView::Fixed);
00172   itsAnimationView->horizontalHeader()->setDefaultSectionSize(10);
00173   itsAnimationView->horizontalHeader()->hide();
00174 
00175   itsAnimationView->verticalHeader()->setResizeMode(QHeaderView::Fixed);
00176   itsAnimationView->verticalHeader()->setDefaultSectionSize(25);
00177 
00178   AnimationDelegate *delegate = new AnimationDelegate(this);
00179   itsAnimationView->setItemDelegate(delegate);
00180 
00181   itsAnimationView->setDragDropMode(QAbstractItemView::DragDrop);
00182   itsAnimationView->setDragEnabled(true);
00183 
00184   itsAnimationView->viewport()->installEventFilter(this);
00185 
00186   itsAnimationView->setContextMenuPolicy(Qt::CustomContextMenu);
00187   connect(itsAnimationView, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(animationViewPopup(const QPoint &)));
00188 
00189   //When the frame changes, the animation view should show a column as selected
00190   connect(this, SIGNAL(frameIndexChanged(int)), delegate, SLOT(frameIndexChanged(int)));
00191 
00192   //When a column is selected, the animation frame should change
00193   connect(itsAnimationView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(animationFrameSelected(const QModelIndex &)));
00194 
00195   return itsAnimationView;
00196 }
00197 
00198 //######################################################################
00199 MainWindow::MainWindow() :
00200   itsDBManager(this),
00201   itsCachedFrameLoader(new CachedFrameLoader),
00202   itsFramerate(10.0),
00203   itsPrefsDialog(this),
00204   itsSettings(new QSettings("iLab", "NeoAnnotate"))
00205 {
00206   itsDBManager.updateSettings(itsSettings);
00207 
00208   connect(&itsDBManager, SIGNAL(openVideo(QString)), this, SLOT(openVideo(QString)));
00209 
00210   statusBar()->insertPermanentWidget(0, &itsDBStatusLabel);
00211   statusBar()->insertPermanentWidget(1, new QLabel(" | "));
00212   statusBar()->insertPermanentWidget(2, &itsAnnotatorLabel);
00213   itsDBStatusLabel.setText(tr("Not Connected To DB"));
00214   itsAnnotatorLabel.setText(tr("No Annotator Selected"));
00215 
00216   itsDBManager.connectToDb();
00217   while(itsDBManager.isConnected() == false)
00218   {
00219     QMessageBox msgBox(QMessageBox::Critical, "Not Connected To Database",
00220         "You must connect to a database to use this application",
00221         QMessageBox::Abort | QMessageBox::Retry);
00222     if(msgBox.exec() == QMessageBox::Retry)
00223     {
00224       itsDBManager.connectToDb();
00225     }
00226     else
00227     {
00228       qDebug() << "Exiting. ";
00229       QCoreApplication::exit(0);
00230       exit(0);
00231     }
00232   }
00233 
00234   buildWindow();
00235 }
00236 
00237 //######################################################################
00238 void MainWindow::setDBStatusLabel(QString text)
00239 {
00240   itsDBStatusLabel.setText(text);
00241 }
00242 
00243 //######################################################################
00244 void MainWindow::setAnnotatorLabel(QString text)
00245 {
00246   itsAnnotatorLabel.setText(text);
00247 }
00248 
00249 //######################################################################
00250 void MainWindow::createTimeline()
00251 {
00252   //Construct the new timeline using the calculated duration
00253   itsTimeline = new QTimeLine(1, this);
00254 
00255   itsTimeline->setCurveShape(QTimeLine::LinearCurve);
00256 }
00257 
00258 //######################################################################
00259 QGroupBox* MainWindow::createTransport()
00260 {
00261   //Clicking the push button will start the progress bar animation
00262   itsPlayButton = new QPushButton(QIcon("src/NeovisionII/NeoAnnotate/icons/Play-icon.png"),"");
00263   connect(itsPlayButton, SIGNAL(clicked()), this, SLOT(playPushed()));
00264 
00265   //Create a slider to show/modify the current frame
00266   itsProgressBar = new QSlider(this);
00267   itsProgressBar->setOrientation(Qt::Horizontal);
00268   itsProgressBar->setRange(0,0);
00269 
00270   connect(itsProgressBar, SIGNAL(sliderMoved(int)), this, SLOT(changeTime(int)));
00271   connect(itsProgressBar, SIGNAL(sliderPressed()), this, SLOT(sliderPressed()));
00272   connect(itsProgressBar, SIGNAL(sliderReleased()), this, SLOT(sliderReleased()));
00273 
00274   itsFrameLabel = new QLabel(this);
00275   itsFrameLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
00276   itsFrameLabel->setMaximumSize(90, 30);
00277   itsFrameLabel->setMinimumSize(90, 30);
00278 
00279   //Create a layout to put the start button
00280   //and slider next to each other
00281   QHBoxLayout *transportLayout = new QHBoxLayout;
00282   transportLayout->addWidget(itsPlayButton);
00283   transportLayout->addWidget(itsProgressBar);
00284   transportLayout->addWidget(itsFrameLabel);
00285 
00286   //Create a group box to hold this layout
00287   QGroupBox *transportBox = new QGroupBox("Transport");
00288   transportBox->setLayout(transportLayout);
00289   transportBox->setFlat(false);
00290 
00291   return transportBox;
00292 }
00293 
00294 
00295 //######################################################################
00296 void MainWindow::buildWindow()
00297 {
00298   itsMainDisplay   = new MainDisplay(this);
00299   itsObjectManager = new AnnotationObjectManager(this);
00300 
00301   connect(itsMainDisplay, SIGNAL(addVertex(QPointF)),    itsObjectManager, SLOT(addVertex(QPointF)));
00302   connect(itsMainDisplay, SIGNAL(removeVertex(QPointF)), itsObjectManager, SLOT(removeVertex(QPointF)));
00303 
00304   createMenuBar();
00305   createTimeline();
00306   createToolbar();
00307   QGroupBox* transport = createTransport();
00308   QWidget* objectList  = createObjectList();
00309 
00310   //Create the animation controls
00311   QTableView* animationControls = createAnimationControls();
00312   itsObjectManager->setAnimationView(animationControls);
00313 
00314   //Create a new layout/widget to hold the object list and transport box
00315   QVBoxLayout * bottomToolsLayout = new QVBoxLayout;
00316   bottomToolsLayout->addWidget(animationControls);
00317 
00318   bottomToolsLayout->addWidget(transport);
00319   QWidget* bottomToolsWidget = new QWidget;
00320   bottomToolsWidget->setLayout(bottomToolsLayout);
00321 
00322   QDockWidget * ObjectListToolbar = new QDockWidget("Object List");
00323   ObjectListToolbar->setWidget(objectList);
00324   ObjectListToolbar->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
00325   addDockWidget(Qt::LeftDockWidgetArea, ObjectListToolbar);
00326 
00327   //Create a splitter to split the window between the main display, and the controls
00328   QSplitter *mainSplitter = new QSplitter(this);
00329   mainSplitter->setOrientation(Qt::Vertical);
00330   mainSplitter->addWidget(itsMainDisplay);
00331   mainSplitter->addWidget(bottomToolsWidget);
00332   QList<int> sizesList;
00333   sizesList.push_back(400);
00334   sizesList.push_back(100);
00335   mainSplitter->setSizes(sizesList);
00336 
00337   //Set up this splitter as the only item in the main layout
00338   QVBoxLayout* mainLayout = new QVBoxLayout;
00339   mainLayout->addWidget(mainSplitter);
00340 
00341   //Perform some kind of Qt magic to display the main layout
00342   QWidget *centralWidget = new QWidget;
00343   setCentralWidget(centralWidget);
00344   centralWidget->setLayout(mainLayout);
00345 
00346   //Connect the play button
00347   connect(itsTimeline, SIGNAL(frameChanged(int)), itsProgressBar, SLOT(setValue(int)));
00348   connect(itsTimeline, SIGNAL(frameChanged(int)), this, SLOT(updateFrame(int)));
00349   connect(this, SIGNAL(pausePlayback(bool)), itsTimeline, SLOT(setPaused(bool)));
00350 
00351   setWindowTitle(tr("NeoVision II Video Annotation Tool"));
00352 
00353   //Grab and paint the first frame
00354   //updateFrame(itsCachedFrameLoader->getFrameRange().getFirst());
00355 }
00356 
00357 ////////////////////////////////////////////////////////////////////////
00358 // SLOTS
00359 ////////////////////////////////////////////////////////////////////////
00360 
00361 //######################################################################
00362 void MainWindow::updateFrame(int frameNum)
00363 {
00364   itsCurrentFrame = frameNum;
00365   itsFrameLabel->setText(QString("Frame: %1").arg(frameNum, 3, 10, QChar(' ')));
00366   itsMainDisplay->setImage(itsCachedFrameLoader->getFrame(frameNum));
00367 
00368   emit(frameIndexChanged(frameNum-itsCachedFrameLoader->getFrameRange().getFirst()));
00369 
00370   // Scroll the animation view so that the current frame is always in the middle
00371   if(itsTimeline->state() == QTimeLine::Running)
00372         {       
00373                 QModelIndex root = itsAnimationView->indexAt(QPoint(0,0));
00374                 QModelIndex currIndex = root.child(1, frameNum);
00375                 itsAnimationView->scrollTo(currIndex, QAbstractItemView::PositionAtCenter);
00376                 itsAnimationView->scrollToTop();
00377         }
00378 }
00379 
00380 
00381 //######################################################################
00382 void MainWindow::addObject()
00383 {
00384   //Find the center of the current viewport
00385   QTransform t = itsMainDisplay->viewportTransform();
00386 
00387   float w = itsMainDisplay->width();
00388   float h = itsMainDisplay->height();
00389 
00390   float sx = t.m11();
00391   float sy = t.m22();
00392   float tx = -t.m31();
00393   float ty = -t.m32();
00394 
00395   QPointF center_view((w/2.0)/sx, (h/2.0)/sy);
00396   QPointF topLeft(tx/sx, ty/sy);
00397   QPointF center = center_view + topLeft;
00398 
00399   //Create a new AnnotationObject, and put it at the center of the viewport,
00400   //starting at the current frame
00401   AnnotationObject * obj = new AnnotationObject(
00402       itsCurrentFrame,
00403       itsCachedFrameLoader->getFrameRange(),
00404       center
00405       );
00406 
00407   obj->setPos(center);
00408 
00409   //Let the object know about the current frame
00410   obj->frameChanged(itsTimeline->currentFrame());
00411 
00412   itsObjectManager->addObject(obj);
00413   itsMainDisplay->addObject(obj);
00414 
00415   connect(itsTimeline, SIGNAL(frameChanged(int)), obj, SLOT(frameChanged(int)));
00416 }
00417 
00418 void MainWindow::playPushed()
00419 {
00420   if(itsTimeline->state() == QTimeLine::NotRunning)
00421 
00422   {
00423     itsPlayButton->setDown(true);
00424     itsTimeline->start();
00425   }
00426   else if(itsTimeline->state() == QTimeLine::Paused)
00427   {
00428     itsPlayButton->setDown(true);
00429     itsTimeline->resume();
00430   }
00431   else if(itsTimeline->state() == QTimeLine::Running)
00432   {
00433     itsPlayButton->setDown(false);
00434     itsTimeline->setPaused(true);
00435   }
00436 }
00437 
00438 void MainWindow::changeTime(int frameNum)
00439 {
00440   //Convert from frame number to milliseconds
00441   int ms = 1.0/itsFramerate * qreal(frameNum - itsCachedFrameLoader->getFrameRange().getFirst()) * 1000.0;
00442 
00443   itsTimeline->setCurrentTime(ms);
00444 }
00445 
00446 void MainWindow::sliderPressed()
00447 {
00448   if(itsTimeline->state() == QTimeLine::Running)
00449   {
00450     timelineWasRunning = true;
00451     itsTimeline->setPaused(true);
00452   }
00453   else
00454   {
00455     timelineWasRunning = false;
00456   }
00457 }
00458 
00459 void MainWindow::sliderReleased()
00460 {
00461   if(timelineWasRunning)
00462   {
00463     //itsTimeline->setPaused(false);
00464     itsTimeline->start();
00465   }
00466 }
00467 
00468 
00469 void MainWindow::animationViewPopup(const QPoint & pos)
00470 {
00471   QPoint globalPos = itsAnimationView->viewport()->mapToGlobal(pos);
00472   int column = itsAnimationView->indexAt(pos).column();
00473   int row    = itsAnimationView->indexAt(pos).row();
00474 
00475   itsObjectManager->constructAnimationContextMenu(globalPos, row, column);
00476 }
00477 
00478 bool MainWindow::eventFilter(QObject * watched, QEvent * event)
00479 {
00480   if(watched == itsAnimationView->viewport())
00481   {
00482     if(event->type() == QEvent::MouseButtonPress)
00483     {
00484       //The user has pressed the mouse button over the animation view
00485 
00486       //Grab the index that was clicked on
00487       QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
00488       QPoint pos = mouseEvent->pos();
00489       QModelIndex index = itsAnimationView->indexAt(pos);
00490 
00491       //Change the framenumber
00492       int frameNumber = index.column() + itsCachedFrameLoader->getFrameRange().getFirst();
00493       this->changeTime(frameNumber);
00494 
00495       //Inform the manager that a cell was clicked on so that it can highlight
00496       //the proper row, and inform the animationmodel of the click in case
00497       //there is a drag and drop
00498       itsObjectManager->setLastAnimViewClick(index);
00499 
00500       return false;
00501 
00502     }
00503     else if(event->type() == QEvent::MouseButtonRelease)
00504     {
00505       //The user has released the mouse button over the animation view
00506 
00507       //Grab the index that was clicked on
00508       QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
00509       QPoint pos = mouseEvent->pos();
00510       int column = itsAnimationView->indexAt(pos).column();
00511       int frameNumber = column + itsCachedFrameLoader->getFrameRange().getFirst();
00512 
00513       //Change the frame number
00514       this->changeTime(frameNumber);
00515 
00516       return false;
00517     }
00518     else if(event->type() == QEvent::KeyPress)
00519     {
00520 
00521     }
00522   }
00523   return false;
00524 }
00525 
00526 void MainWindow::animationFrameSelected(const QModelIndex & index)
00527 {
00528   int frameNumber = index.column() + itsCachedFrameLoader->getFrameRange().getFirst();
00529   updateFrame(frameNumber);
00530   changeTime(frameNumber);
00531 }
00532 
00533 //void MainWindow::saveAnnotation()
00534 //{
00535 //  //Get the filename from a save file dialog
00536 //  //QString filename = QFileDialog::getSaveFileName(this, "Export Annotation as XML", "", "XML (*.xml)");
00537 //  QFileDialog dialog(this, "Choose a directory");
00538 //  dialog.setFileMode(QFileDialog::DirectoryOnly);
00539 //  if(dialog.exec())
00540 //  {
00541 //    QString directoryName = dialog.selectedFiles()[0];
00542 //
00543 //    std::map<int, std::map<int, AnnotationObjectFrame > > animation = itsObjectManager->renderAnimations();
00544 //
00545 //    saveAnnotationToXML(directoryName, animation);
00546 //  }
00547 //}
00548 
00549 //void MainWindow::loadAnnotation()
00550 //{
00551 //  LINFO("Loading...");
00552 //  QFileDialog dialog(this, "Choose a directory");
00553 //  dialog.setFileMode(QFileDialog::DirectoryOnly);
00554 //  if(dialog.exec())
00555 //  {
00556 //    QString directoryName = dialog.selectedFiles()[0];
00557 //    qDebug() << "Directory Name: " << directoryName;
00558 //
00559 //    loadAnnotationFromXML(directoryName);
00560 //  }
00561 //}
00562 
00563 void MainWindow::openVideo(QString fileName)
00564 {
00565   if(fileName == "") return;
00566 
00567   itsFileName = fileName;
00568   itsCachedFrameLoader->loadVideo(itsFileName);
00569 
00570   updateFrame(0);
00571 
00572   //Grab the frame range from the framegrabber
00573   FrameRange frameRange = itsCachedFrameLoader->getFrameRange();
00574 
00575   //Compute the total number of frames
00576   int numFrames = frameRange.getLast() - frameRange.getFirst() - 1;
00577 
00578   //Compute the total duration of the movie
00579   qreal duration_s = 1.0/(itsFramerate / qreal(numFrames));
00580   qreal duration_ms = 1000.0 * duration_s;
00581 
00582   itsTimeline->setDuration(duration_ms);
00583 
00584   //Set the timelines first and last frames
00585   itsTimeline->setFrameRange(frameRange.getFirst(),frameRange.getLast()-1);
00586 
00587   itsProgressBar->setRange(itsTimeline->startFrame(),itsTimeline->endFrame());
00588 }
00589 
00590 void MainWindow::openVideo()
00591 {
00592   QFileDialog dialog(this, tr("Choose a .mgzJ file"));
00593   dialog.setFileMode(QFileDialog::ExistingFile);
00594   dialog.setNameFilter(tr("mgzJ Files (*.mgzJ)"));
00595 
00596   if(dialog.exec())
00597   {
00598      openVideo(dialog.selectedFiles()[0]);
00599   }
00600 }
00601 
00602 /*
00603 //TODO: This should be moved out of here into it's own class which inherits from some kind of general state importer/exporter class.
00604 //TODO: Implement a compact binary output for this data in addition to the bulky xml
00605 void MainWindow::saveAnnotationToXML(QString directoryName, std::map<int, std::map<int, AnnotationObjectFrame > > animation)
00606 {
00607   std::vector<QString> frame_filenames;
00608 
00609   std::map<int, std::map<int, AnnotationObjectFrame> >::iterator animIt;
00610 
00611   for(animIt = animation.begin(); animIt != animation.end(); animIt++)
00612   {
00613 
00614     int fnum = animIt->first;
00615 
00616     //Open the file for this frame
00617     QString filename = directoryName + QString("/frame%1.xml").arg(fnum);
00618 
00619     QString frame_filename = QString("frame%1").arg(fnum); 
00620     
00621     QDomDocument frameDoc("frame");
00622 
00623     QDomElement node_scenes = frameDoc.createElement("scenes");
00624     frameDoc.appendChild(node_scenes);
00625 
00626     QDomElement node_annotation = frameDoc.createElement("annotation");
00627     node_scenes.appendChild(node_annotation);
00628     
00629     //TODO: This should be replaced with the real frame filename
00630     QDomElement node_filename = frameDoc.createElement("filename");
00631     node_annotation.appendChild(node_filename);
00632     QDomText node_filename_t = frameDoc.createTextNode(QString("%1").arg(fnum));
00633     node_filename.appendChild(node_filename_t);
00634 
00635     QDomElement node_framenumber = frameDoc.createElement("framenumber");
00636     node_annotation.appendChild(node_framenumber);
00637     QDomText node_framenumber_t = frameDoc.createTextNode(QString("%1").arg(fnum));
00638     node_framenumber.appendChild(node_framenumber_t);
00639 
00640     //TODO: What's this?
00641     QDomElement node_source = frameDoc.createElement("source");
00642     node_annotation.appendChild(node_source);
00643     QDomText node_source_t = frameDoc.createTextNode("NeoVision");
00644     node_source.appendChild(node_source_t);
00645 
00646     //Grab all of the objects in this frame
00647     std::map<int, AnnotationObjectFrame> objects = animIt->second;
00648     std::map<int, AnnotationObjectFrame>::iterator objectsIt;
00649 
00650     //Loop through all of the objects and put them into the xml tree
00651     for(objectsIt = objects.begin(); objectsIt != objects.end(); objectsIt++)
00652     {
00653       AnnotationObjectFrame f = objectsIt->second;
00654 
00655       QDomElement node_object = frameDoc.createElement("object");
00656       node_object.setAttribute("vis", f.ObjectFrameState.visible?"1":"0");
00657       node_object.setAttribute("key", f.ObjectFrameState.is_keyframe?"1":"0");
00658       node_annotation.appendChild(node_object);
00659 
00660       QDomElement node_name = frameDoc.createElement("name");
00661       node_object.appendChild(node_name);
00662       QDomText node_name_t = frameDoc.createTextNode(f.ObjectName);
00663       node_name.appendChild(node_name_t);
00664 
00665       QDomElement node_id = frameDoc.createElement("id");
00666       node_object.appendChild(node_id);
00667       QDomText node_id_t = frameDoc.createTextNode(QString("%1").arg(f.ObjectId));
00668       node_id.appendChild(node_id_t);
00669 
00670       QDomElement node_description = frameDoc.createElement("description");
00671       node_object.appendChild(node_description);
00672       QDomText node_description_t = frameDoc.createTextNode(f.ObjectType);
00673       node_description.appendChild(node_description_t);
00674 
00675       //Insert the position of the object into the file.  Note that this is
00676       //_only_ so that we can reload this file to get an exact representation
00677       //of the original keyframing. This position is absolute, and all of the
00678       //vertex positions are absolute as well so that when we reload, we will
00679       //need to subtract the object position from the vertex positions to make
00680       //them relative again.
00681       QDomElement node_x = frameDoc.createElement("x");
00682       node_object.appendChild(node_x);
00683       QDomText node_x_t = frameDoc.createTextNode(QString("%1").arg(f.ObjectFrameState.pos.x()));
00684       node_x.appendChild(node_x_t);
00685       QDomElement node_y = frameDoc.createElement("y");
00686       node_object.appendChild(node_y);
00687       QDomText node_y_t = frameDoc.createTextNode(QString("%1").arg(f.ObjectFrameState.pos.y()));
00688       node_y.appendChild(node_y_t);
00689 
00690       QDomElement node_polygon = frameDoc.createElement("polygon");
00691       node_object.appendChild(node_polygon);
00692 
00693       //Loop through all of the vertices and append them to the object branch
00694       std::map<int, ObjectAnimation::FrameState>::iterator vIt;
00695       for(vIt = f.VertexFrames.begin(); vIt != f.VertexFrames.end(); vIt++)
00696       {
00697         ObjectAnimation::FrameState vState = vIt->second;
00698         QDomElement node_pt = frameDoc.createElement("pt");
00699         node_pt.setAttribute("vis", vState.visible?"1":"0");
00700         node_pt.setAttribute("key", vState.is_keyframe?"1":"0");
00701         node_polygon.appendChild(node_pt);
00702 
00703         QDomElement node_x = frameDoc.createElement("x");
00704         node_pt.appendChild(node_x);
00705         QDomText node_x_t = frameDoc.createTextNode(QString("%1").arg(vState.pos.x()));
00706         node_x.appendChild(node_x_t);
00707 
00708         QDomElement node_y = frameDoc.createElement("y");
00709         node_pt.appendChild(node_y);
00710         QDomText node_y_t = frameDoc.createTextNode(QString("%1").arg(vState.pos.y()));
00711         node_y.appendChild(node_y_t);
00712 
00713         QDomElement node_id = frameDoc.createElement("id");
00714         node_pt.appendChild(node_id);
00715         QDomText node_id_t = frameDoc.createTextNode(QString("%1").arg(vIt->first));
00716         node_id.appendChild(node_id_t);
00717       }
00718     }
00719 
00720     //Write the file to disk
00721     QString fullFrameFilename = directoryName + "/" + frame_filename + ".xml";
00722     QFile frame_file(fullFrameFilename);
00723     frame_filenames.push_back(fullFrameFilename);
00724     if(!frame_file.open(QIODevice::WriteOnly | QIODevice::Text))
00725     { 
00726       qDebug() << "Couldn't write " << fullFrameFilename << "!";
00727       return; 
00728     }
00729     QTextStream out(&frame_file);
00730     out << frameDoc.toString();
00731   }
00732 
00733 
00734   QDomDocument indexDoc("index");
00735 
00736   QDomElement node_scenes = indexDoc.createElement("scenes");
00737   indexDoc.appendChild(node_scenes);
00738 
00739   std::vector<QString>::iterator includeIt;
00740   for(includeIt = frame_filenames.begin(); includeIt != frame_filenames.end(); includeIt++)
00741   {
00742     QDomElement node_include = indexDoc.createElement("include");
00743     node_include.setAttribute("filename", *includeIt);
00744     node_scenes.appendChild(node_include);
00745   }
00746 
00747   //Write the file to disk
00748   QString indexFilename = directoryName + "/index.xml";
00749   QFile index_file(indexFilename);
00750   if(!index_file.open(QIODevice::WriteOnly | QIODevice::Text))
00751   { 
00752     qDebug() << "Couldn't write " << indexFilename << "!";
00753     return; 
00754   }
00755   QTextStream out(&index_file);
00756   out << indexDoc.toString();
00757 }
00758 
00759 
00760 void MainWindow::loadAnnotationFromXML(QString Directory)
00761 {
00762   QString indexFileName = Directory + "/index.xml";
00763   QDomDocument indexDoc("index");
00764   QFile file(indexFileName);
00765   if(!file.open(QIODevice::ReadOnly))
00766   {
00767     LINFO("Could Not Open %s", indexFileName.toStdString().c_str());
00768     return;
00769   }
00770   if(!indexDoc.setContent(&file))
00771   {
00772     LINFO("Could Not Open %s - Bad File", indexFileName.toStdString().c_str());
00773     file.close();
00774     return;
00775   }
00776   file.close();
00777 
00778   //Load the document, and grab the scenes branch
00779   QDomElement indexDocElem = indexDoc.documentElement();
00780   QDomNode node_scenes = indexDoc.elementsByTagName("scenes").item(0);
00781   if(node_scenes.isNull())
00782   {
00783     LINFO("Error - malformed index.xml file! Line: %d", __LINE__);
00784     return;
00785   }
00786 
00787   //Clear the Annotation Object Manager
00788   itsObjectManager->clear();
00789 
00790   //Get the frame range from the framegrabber so that we can only load
00791   //animation for the relavent frames.
00792   FrameRange videoFrameRange = itsCachedFrameLoader->getFrameRange();
00793 
00794   //Loop through each include node (frame number) in the scenes
00795   //TODO: Parse out the frame number and just continue if we are out of the frame range
00796   QDomNodeList fileList = node_scenes.childNodes();
00797   for(int fileIdx = 0; fileIdx < fileList.size(); fileIdx++)
00798   {
00799     //Load the XML file included in the index
00800     QDomNode node_file = fileList.at(fileIdx);
00801     QString frameFileName = node_file.attributes().namedItem("filename").toAttr().value();
00802     QDomDocument frameDoc("frame");
00803     QFile file(frameFileName);
00804     if(!file.open(QIODevice::ReadOnly))
00805     {
00806       LINFO("Could Not Open %s", frameFileName.toStdString().c_str());
00807       return;
00808     }
00809     if(!frameDoc.setContent(&file))
00810     {
00811       LINFO("Could Not Open %s - Bad File", frameFileName.toStdString().c_str());
00812       file.close();
00813       return;
00814     }
00815     file.close();
00816 
00817     //Load the document
00818     QDomElement frameDocElem = frameDoc.documentElement();
00819 
00820     //Find the framenumber for this document
00821     QDomNode node_framenumber = frameDocElem.elementsByTagName("framenumber").item(0);
00822     if(node_framenumber.isNull())
00823     { LINFO("Error - malformed xml file! Line: %d", __LINE__); return; }
00824     int fnum = node_framenumber.firstChild().nodeValue().toInt();
00825 
00826     //Loop through all of the objects in the document
00827     QDomNodeList objects = frameDocElem.elementsByTagName("object");
00828     for(int objIdx=0; objIdx<objects.size(); objIdx++)
00829     {
00830       QDomNode node_object = objects.at(objIdx);
00831 
00832       //Grab the object's ID
00833       int objectId = node_object.firstChildElement("id").firstChild().nodeValue().toInt();
00834 
00835       //Find out if this frame is a keyframe for this object
00836       bool object_isKey = node_object.attributes().namedItem("key").toAttr().value().toInt();
00837 
00838       //Find out if the object is visible in this frame
00839       bool object_isVis = node_object.attributes().namedItem("vis").toAttr().value().toInt();
00840       
00841       //Grab the object's position
00842       QPointF objectPos;
00843       objectPos.setX(node_object.firstChildElement("x").firstChild().nodeValue().toDouble());
00844       objectPos.setY(node_object.firstChildElement("y").firstChild().nodeValue().toDouble());
00845       
00846       //Read the object's vertices' states and store them in VertexFrames
00847       QDomNode node_vertex = node_object.firstChildElement("polygon").firstChildElement("pt");
00848       std::map<int, ObjectAnimation::FrameState> VertexFrames;
00849       while(!node_vertex.isNull())
00850       {
00851         ObjectAnimation::FrameState vertexState;
00852         vertexState.pos.setX(node_vertex.firstChildElement("x").firstChild().nodeValue().toDouble());
00853         vertexState.pos.setY(node_vertex.firstChildElement("y").firstChild().nodeValue().toDouble());
00854         vertexState.pos -= objectPos;
00855         vertexState.visible = node_vertex.attributes().namedItem("vis").toAttr().value().toInt();
00856         vertexState.is_keyframe = node_vertex.attributes().namedItem("key").toAttr().value().toInt();
00857 
00858         int vertexId = node_vertex.firstChildElement("id").firstChild().nodeValue().toDouble();
00859         VertexFrames[vertexId] = vertexState;
00860 
00861         node_vertex = node_vertex.nextSibling();
00862       }
00863 
00864       //Check to see if the object already exists in the database
00865       AnnotationObject* obj = itsObjectManager->getObjectById(objectId);
00866       if(obj == NULL)
00867       {
00868         //If the object is not in the database, and we have found it's first keyframe then we should
00869         //create it and insert it into storage.
00870 
00871         QString name        = node_object.firstChildElement("name").firstChild().nodeValue();
00872         int category        = node_object.firstChildElement("description").firstChild().nodeValue().toInt();
00873 
00874         //Create a new object and insert it into the Object Manager
00875         obj =
00876           new AnnotationObject(
00877               fnum,
00878               videoFrameRange,
00879               objectPos, name, category
00880               );
00881         obj->forceId(objectId);
00882         obj->clearAnimation();
00883         obj->setVertices(VertexFrames);
00884 
00885         itsObjectManager->addObject(obj);
00886         itsMainDisplay->addObject(obj);
00887         connect(itsTimeline, SIGNAL(frameChanged(int)), obj, SLOT(frameChanged(int)));
00888       }
00889 
00890       //Check to see if we have a new keyframe for our object
00891       if(object_isKey)
00892       {
00893         obj->setKeyframe(fnum, objectPos, object_isVis);
00894       }
00895 
00896       //Roll through all of the vertices to see if they have any keyframes at this frame
00897       std::map<int, ObjectAnimation::FrameState>::iterator vIt;
00898       for(vIt=VertexFrames.begin(); vIt!=VertexFrames.end(); vIt++)
00899       {
00900         ObjectAnimation::FrameState vertexState = vIt->second;
00901         if(vertexState.is_keyframe)
00902         {
00903           AnnotationObjectVertex* vertex = obj->getVertexById(vIt->first);
00904           vertex->setKeyframe(fnum, vertexState.pos, vertexState.visible);
00905         }
00906       }
00907 
00908     }
00909   }
00910 
00911   LINFO("Finished Import");
00912 }
00913 */
00914 
00915 void MainWindow::saveAnnotationToDB()
00916 {
00917   itsDBManager.saveAnnotation();
00918 }
00919 
00920 void MainWindow::openAnnotationFromDB()
00921 {
00922   itsDBManager.openAnnotation();
00923 }
00924 
00925 void MainWindow::createDBEntry()
00926 {
00927   itsDBManager.createDBEntry();
00928 }
00929 
00930 void MainWindow::openPrefsDialog()
00931 {
00932 
00933   if(itsSettings->contains("archiveLoc"))
00934     itsPrefsDialog.archiveLocEdit->setText(itsSettings->value("archiveLoc").toString());
00935   if(itsSettings->contains("workingLoc"))
00936     itsPrefsDialog.workingLocEdit->setText(itsSettings->value("workingLoc").toString());
00937   if(itsSettings->contains("incomingLoc"))
00938     itsPrefsDialog.incomingLocEdit->setText(itsSettings->value("incomingLoc").toString());
00939 
00940   if(itsPrefsDialog.exec())
00941   {
00942     QString archiveLoc  = itsPrefsDialog.archiveLocEdit->text();
00943     QString workingLoc  = itsPrefsDialog.workingLocEdit->text();
00944     QString incomingLoc = itsPrefsDialog.incomingLocEdit->text();
00945 
00946     itsSettings->setValue("archiveLoc",  archiveLoc);
00947     itsSettings->setValue("workingLoc",  workingLoc);
00948     itsSettings->setValue("incomingLoc", incomingLoc);
00949 
00950   }
00951 }
00952 #endif //MAINWINDOW_C
00953 
Generated on Sun May 8 08:41:02 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3