commands.cpp
Go to the documentation of this file.
00001 #include <pcl/apps/cloud_composer/commands.h>
00002 #include <pcl/apps/cloud_composer/tool_interface/abstract_tool.h>
00003 #include <pcl/apps/cloud_composer/project_model.h>
00004 #include <pcl/apps/cloud_composer/merge_selection.h>
00005 
00006 pcl::cloud_composer::CloudCommand::CloudCommand (QList <const CloudComposerItem*> input_data, QUndoCommand* parent)
00007   : QUndoCommand (parent)
00008   , original_data_ (input_data)
00009   , can_use_templates_(false)
00010   , template_type_ (-1)
00011 {
00012 
00013 }
00014 
00015 pcl::cloud_composer::CloudCommand::~CloudCommand ()
00016 {
00017   qDebug () << "Command Destructor";
00018   //If we have removed items, we delete them
00019   if (!last_was_undo_)
00020   {
00021     qDebug () << "Last was redo, removing original items ";
00022     QList <QStandardItem*> items_to_remove = removed_to_parent_map_.keys ();
00023     foreach (QStandardItem* to_remove, items_to_remove)
00024     {
00025       if (to_remove)
00026         delete to_remove;
00027     }
00028   }
00029   else
00030   {
00031     qDebug () << "Last was undo, removing new items";
00032     foreach (OutputPair output_pair, output_data_)
00033     {
00034       QList <CloudComposerItem*> new_items = output_pair.output_items_;
00035       foreach (CloudComposerItem* item, new_items)
00036         if (item)
00037           delete item;
00038     }
00039     
00040   }
00041 }
00043 
00044 void
00045 pcl::cloud_composer::CloudCommand::setProjectModel (ProjectModel* model)
00046 {
00047   project_model_ = model;
00048 }
00049 
00050 bool
00051 pcl::cloud_composer::CloudCommand::canUseTemplates (ConstItemList &input_data)
00052 {
00053   //Make sure the input list isn't empty
00054   if (input_data.size () == 0)
00055   {
00056     qCritical () << "Cannot call a templated tool on an empty input in CloudCommand::executeToolOnTemplateCloud!";
00057     template_type_ = -2;
00058     return false;
00059   }
00060   //Make sure all input items are clouds
00061   QList <const CloudItem*> cloud_items;
00062   foreach (const CloudComposerItem* item, input_data)
00063   {
00064     const CloudItem* cloud_item = dynamic_cast<const CloudItem*> (item);
00065     if (cloud_item)
00066       cloud_items.append (cloud_item);
00067   }
00068   if (cloud_items.size () != input_data.size ())
00069   {
00070     qCritical () << "All input items are not clouds in CloudCommand::executeToolOnTemplateCloud!";
00071     template_type_ = -3;
00072     return false;
00073   }
00074   
00075   // Now make sure all input clouds have the same templated type
00076   int type = cloud_items.value (0)->getPointType ();
00077   foreach (const CloudItem* cloud_item, cloud_items)
00078   {
00079     if (cloud_item->getPointType () != type)
00080     {
00081       qCritical () << "All input point cloud template types in CloudCommand::executeToolOnTemplateCloud are not the same!";
00082       qCritical () << cloud_item->text () << "'s type does not match "<<cloud_items.value (0)->type ();
00083       template_type_ = -3;
00084       return false;
00085     }
00086   }
00087   template_type_ = type;
00088   can_use_templates_ = true;
00089   return true;
00090 }
00091 
00092 /*
00093 QList <pcl::cloud_composer::CloudComposerItem*> 
00094 pcl::cloud_composer::CloudCommand::executeToolOnTemplateCloud (AbstractTool* tool, ConstItemList &input_data)
00095 {
00096   QList <CloudComposerItem*> output;
00097   // If can_use_templates_ is false and type is -1 we haven't checked if we can yet
00098   if (!can_use_templates_ && template_type_ == -1)
00099     this->canUseTemplates (input_data);
00100   
00101   
00102   //If this is true now, we can go ahead and run it
00103   if (can_use_templates_ && template_type_ >= 0)
00104   {
00105     output = tool->performAction( input_data, static_cast<PointTypeFlags::PointType> (template_type_));
00106   }
00107   else
00108   {
00109     qDebug () << "Tried CloudCommand::executeToolOnTemplateCloud but input data was not templated clouds!";
00110   }
00111   return output;
00112   
00113 }
00114 */
00116 
00117 bool 
00118 pcl::cloud_composer::CloudCommand::replaceOriginalWithNew (QList <const CloudComposerItem*> originals, QList <CloudComposerItem*> new_items)
00119 { 
00120   //Find the input item's parent
00121   if (originals.size () < 1)
00122   {
00123     qCritical () << "No items to replace specified!";
00124     return false;
00125   }
00126     
00127   QStandardItem* parent_item = originals.value(0)->parent ();
00128   //Verify that all items have same parent
00129   foreach (const CloudComposerItem* item, originals)
00130   {
00131     if (item->parent () != parent_item)
00132     {
00133       qCritical () << "All original items must have same parent!";
00134       return false;
00135     }
00136   }
00137   // If parent is 0, it's parent is invisiblerootitem (That's how Qt defines it... boo!)
00138   if (parent_item == 0)
00139     parent_item = project_model_->invisibleRootItem ();
00140   
00141   //Now remove all the originals
00142   foreach (const CloudComposerItem* item, originals)
00143   {
00144     QPersistentModelIndex original_index = QPersistentModelIndex(project_model_->indexFromItem (item));
00145     if (!original_index.isValid ())
00146     {
00147       qCritical () << "Index of item to replace is not valid!";
00148       return false;
00149     }
00150     QList <QStandardItem*> removed_items = parent_item->takeRow (original_index.row ());
00151     removed_to_parent_map_.insert (removed_items.value(0),parent_item);
00152   }
00153   //Insert the new items below the parent item'
00154   foreach (CloudComposerItem* item, new_items)
00155   {
00156     parent_item->appendRow (item);   
00157   }
00158 
00159   return true;
00160 }
00162 
00163 bool 
00164 pcl::cloud_composer::CloudCommand::restoreOriginalRemoveNew (QList <const CloudComposerItem*> originals, QList <CloudComposerItem*> new_items)
00165 { 
00166   
00167   //Now remove all the new items
00168   foreach (CloudComposerItem* item, new_items)
00169   {
00170     QStandardItem* parent_item = item->parent ();
00171     // If parent is 0, it's parent is invisiblerootitem (That's how Qt defines it... boo!)
00172     if (parent_item == 0)
00173       parent_item = project_model_->invisibleRootItem ();
00174     QPersistentModelIndex to_remove_index = QPersistentModelIndex(project_model_->indexFromItem (item));
00175     if (!to_remove_index.isValid ())
00176     {
00177       qCritical () << "Index of item to remove while restoring originals not valid";
00178       return false;
00179     }
00180     //Take them, they're still stored so we don't worry about them
00181     QList <QStandardItem*> removed = parent_item->takeRow (to_remove_index.row ());
00182   }
00183   //Restore the original items
00184   QMap <QStandardItem*, QStandardItem*>::iterator itr;
00185   foreach (const CloudComposerItem* item, originals)
00186   {
00187     //Point iterator to the correct spot
00188     // Find doesn't modify parameter so it should accept a const pointer, but it can't be because it is templated to the map type
00189     // So we hack to get around this with a const cast
00190     itr = removed_to_parent_map_.find (const_cast<CloudComposerItem*> (item));
00191     QStandardItem* parent = itr.value ();
00192     QStandardItem* original = itr.key ();
00193     parent->appendRow (original);
00194     int num = removed_to_parent_map_.remove (original);
00195     if (num > 1)
00196       qCritical () << "More than one item with same pointer in removed_to_parent_map_, this is undefined behavior";
00197     else if (num == 0) 
00198       qCritical () << "Could not find key in map to remove, not good!";
00199   }
00200 
00201   return true;
00202 }
00203 
00206 
00207 pcl::cloud_composer::ModifyItemCommand::ModifyItemCommand (QList <const CloudComposerItem*> input_data, QUndoCommand* parent)
00208   : CloudCommand (input_data, parent)
00209 { 
00210   
00211 }
00212 
00213 bool
00214 pcl::cloud_composer::ModifyItemCommand::runCommand (AbstractTool* tool)
00215 {
00216   this->setText (tool->getToolName ());
00217   //For modify item cloud command, each selected item should be processed separately
00218   int num_items_returned = 0;
00219   foreach (const CloudComposerItem *item, original_data_)
00220   {
00221     QList <const CloudComposerItem*> input_list;
00222     input_list.append (item);
00223     QList <CloudComposerItem*> output;
00224     if (canUseTemplates(input_list))
00225       output = tool->performAction (input_list, static_cast<PointTypeFlags::PointType> (template_type_));
00226     else
00227       output = tool->performAction (input_list);
00228     if (output.size () == 0)
00229       qWarning () << "Warning: Tool " << tool->getToolName () << "returned no item in a ModifyItemCommand";
00230     else 
00231     {
00232       OutputPair output_pair = {input_list, output};
00233       output_data_.append (output_pair);
00234       num_items_returned++;
00235     }
00236     if (output.size () > 1)
00237     {
00238       qCritical () << "Tool " << tool->getToolName () << "returned multiple items in a ModifyCloudCommand";
00239     }
00240     
00241   }
00242   if (num_items_returned != original_data_.size ())
00243   {
00244     qDebug () << "Modify Item command generated "<<num_items_returned<<" which does not match input of "<<original_data_.size () <<" items";
00245     return true;
00246   }
00247   else
00248   {
00249     return true;
00250   }
00251 }
00253 
00254 void
00255 pcl::cloud_composer::ModifyItemCommand::undo ()
00256 {
00257   last_was_undo_ = true;
00258   qDebug () << "Undo in ModifyItemCommand";
00259   foreach (OutputPair output_pair, output_data_)
00260   {
00261     if (!restoreOriginalRemoveNew (output_pair.input_items_, output_pair.output_items_))
00262       qCritical() << "Failed to restore original items in ModifyItemCommand::undo!";
00263   }
00264   
00265   
00266 }
00268 
00269 void
00270 pcl::cloud_composer::ModifyItemCommand::redo ()
00271 {
00272   last_was_undo_ = false;
00273   foreach (OutputPair output_pair, output_data_)
00274   {
00275     //Replace the input with the output for this pair
00276     if (! replaceOriginalWithNew (output_pair.input_items_, output_pair.output_items_))
00277       qCritical () << "Replacement of old items with new failed in ModifyItemCommand!";
00278   }
00279 
00280 }
00281 
00284 
00285 pcl::cloud_composer::NewItemCloudCommand::NewItemCloudCommand (QList <const CloudComposerItem*> input_data, QUndoCommand* parent)
00286   : CloudCommand (input_data, parent)
00287 {
00288   
00289 }
00290 
00291 bool
00292 pcl::cloud_composer::NewItemCloudCommand::runCommand (AbstractTool* tool)
00293 {
00294   this->setText (tool->getToolName ());
00295   //For new item cloud command, each selected item should be processed separately
00296   //e.g. calculate normals for every selected cloud
00297   int num_new_items = 0;
00298   foreach (const CloudComposerItem *item, original_data_)
00299   {
00300     QList <const CloudComposerItem*> input_list;
00301     input_list.append (item);
00302     QList <CloudComposerItem*> output;
00303     if (canUseTemplates(input_list))
00304       output = tool->performAction (input_list, static_cast<PointTypeFlags::PointType> (template_type_));
00305     else
00306       output = tool->performAction (input_list);
00307     if (output.size () == 0)
00308       qWarning () << "Warning: Tool " << tool->getToolName () << "returned no item in a NewItemCloudCommand";
00309     else 
00310     {
00311       OutputPair output_pair = {input_list, output};
00312       output_data_.append (output_pair);
00313       num_new_items += output.size ();
00314     }
00315     
00316   }
00317   if (num_new_items > 0)
00318   {
00319     qDebug () << "New Item command generated "<<num_new_items<<" new items";
00320     return true;
00321   }
00322   else
00323   {
00324     qWarning () << "New Item command generated no new items!";
00325     return false;
00326   }
00327    
00328 }
00330 
00331 void
00332 pcl::cloud_composer::NewItemCloudCommand::undo ()
00333 {
00334   last_was_undo_ = true;
00335   qDebug () << "Undo in NewItemCloudCommand";
00336   foreach (OutputPair output_pair, output_data_)
00337   {
00338     //Each pair can only have one input item, so get it
00339     const CloudComposerItem* const_input_item = output_pair.input_items_.value (0);
00340     QList <CloudComposerItem*> output_items = output_pair.output_items_;
00341     //Find the input_item index in the project_model_
00342     QModelIndex input_index = project_model_->indexFromItem (const_input_item);
00343     if (!input_index.isValid ())
00344     {
00345       qCritical () << "Index of input cloud item is no longer valid, cannot undo NewItemCloudCommand";
00346       return;
00347     }
00348     //Get a copy of the input item we can modify
00349     QStandardItem* item_to_change = project_model_->itemFromIndex (input_index);
00350     //Remove the items we added 
00351     foreach (CloudComposerItem* output_item, output_items)
00352     {
00353       QModelIndex output_index = project_model_->indexFromItem (output_item);
00354       item_to_change->takeRow (output_index.row ());
00355     }
00356     
00357   }
00358 }
00360 
00361 void
00362 pcl::cloud_composer::NewItemCloudCommand::redo ()
00363 {
00364   last_was_undo_ = false;
00365   qDebug () << "Redo in NewItemCloudCommand - output data size="<<output_data_.size ();
00366   foreach (OutputPair output_pair, output_data_)
00367   {
00368     //Each pair can only have one input item, so get it
00369     const CloudComposerItem* const_input_item = output_pair.input_items_.value (0);
00370     QList <CloudComposerItem*> output_items = output_pair.output_items_;
00371     //Find the input_item index in the project_model_
00372     QPersistentModelIndex input_index = QPersistentModelIndex(project_model_->indexFromItem (const_input_item));
00373     if (!input_index.isValid ())
00374     {
00375       qCritical () << "Index of input cloud item is no longer valid upon command completion!";
00376       return;
00377     }
00378     //Get a copy of the input item we can modify
00379     QStandardItem* input_item = (project_model_->itemFromIndex (input_index));
00380     //Append the output items to the input item
00381     foreach (CloudComposerItem* output_item, output_items)
00382     {
00383       input_item->appendRow (output_item);
00384     }
00385   }
00386 }
00387 
00388 
00391 
00392 pcl::cloud_composer::SplitCloudCommand::SplitCloudCommand (QList <const CloudComposerItem*> input_data, QUndoCommand* parent)
00393   : CloudCommand (input_data, parent)
00394 {
00395   
00396 }
00397 
00398 bool
00399 pcl::cloud_composer::SplitCloudCommand::runCommand (AbstractTool* tool)
00400 {
00401   this->setText (tool->getToolName ());
00402   //For split cloud command, each selected item should be processed separately
00403   //e.g. calculate normals for every selected cloud
00404   int num_new_items = 0;
00405   foreach (const CloudComposerItem *item, original_data_)
00406   {
00407     //Check to see if this is a cloud
00408     QList <const CloudComposerItem*> input_list;
00409     input_list.append (item);
00410     QList <CloudComposerItem*> output;
00411     if (canUseTemplates(input_list))
00412       output = tool->performAction (input_list, static_cast<PointTypeFlags::PointType> (template_type_));
00413     else
00414       output = tool->performAction (input_list);
00415     if (output.size () == 0)
00416       qWarning () << "Warning: Tool " << tool->getToolName () << "returned no item in a SplitCloudCommand";
00417     else 
00418     {
00419       qDebug () << "Split command returned "<<output.size ()<<" items";
00420       OutputPair output_pair = {input_list, output};
00421       output_data_.append (output_pair);
00422       num_new_items += output.size ();
00423     }
00424   }
00425   if (num_new_items > 0)
00426   {
00427     qDebug () << "Split Item command generated "<<num_new_items<<" new items";
00428     return true;
00429   }
00430   else
00431   {
00432     qWarning () << "Split Item command generated no new items!";
00433     return false;
00434   }
00435 
00436 }
00438 
00439 void
00440 pcl::cloud_composer::SplitCloudCommand::undo ()
00441 {
00442   last_was_undo_ = true;
00443   qDebug () << "Undo in SplitItemCloudCommand";
00444   foreach (OutputPair output_pair, output_data_)
00445   {
00446     if (!restoreOriginalRemoveNew (output_pair.input_items_, output_pair.output_items_))
00447       qCritical () << "Failed to restore old cloud in SplitCloudCommand::undo!";
00448   }
00449   
00450 }
00452 
00453 void
00454 pcl::cloud_composer::SplitCloudCommand::redo ()
00455 {
00456   last_was_undo_ = false;
00457   qDebug () << "Redo in SplitItemCloudCommand - output data size="<<output_data_.size ();
00458   foreach (OutputPair output_pair, output_data_)
00459   {
00460     //Replace the input with the output for this pair
00461     if (! replaceOriginalWithNew (output_pair.input_items_, output_pair.output_items_))
00462       qCritical () << "Replacement of old items with new failed in ModifyItemCommand!";
00463   
00464   }
00465 }
00466 
00467 
00470 
00471 pcl::cloud_composer::DeleteItemCommand::DeleteItemCommand (QList <const CloudComposerItem*> input_data, QUndoCommand* parent)
00472   : CloudCommand (input_data, parent)
00473 {
00474   
00475 }
00476 
00477 bool
00478 pcl::cloud_composer::DeleteItemCommand::runCommand (AbstractTool* tool)
00479 {
00480   
00481   //For delete item command, each selected item should be processed separately
00482   //e.g. delete every selected item
00483   int num_new_items = 0;
00484   foreach (const CloudComposerItem *item, original_data_)
00485   {
00486     QList <CloudComposerItem*> output;
00487     QList <const CloudComposerItem*> to_delete;
00488     to_delete.append (item);
00489     OutputPair output_pair = {to_delete, output};
00490     output_data_.append (output_pair);
00491     this->setText ("Delete "+item->text ());
00492   }
00493   if (original_data_.size () > 0)
00494     this->setText ("Delete multiple items");
00495   return true;
00496 }
00498 
00499 void
00500 pcl::cloud_composer::DeleteItemCommand::undo ()
00501 {
00502   last_was_undo_ = true;
00503   //Add the original items back into the model
00504   foreach (OutputPair output_pair, output_data_)
00505   {
00506     if (!restoreOriginalRemoveNew (output_pair.input_items_, output_pair.output_items_))
00507       qCritical () << "Failed to restore items in DeleteItemCommand::undo!";
00508   }
00509 }
00511 
00512 void
00513 pcl::cloud_composer::DeleteItemCommand::redo ()
00514 {
00515   last_was_undo_ = false;
00516   qDebug () << "Redo in DeleteItemCommand - num items to delete="<<output_data_.size ();
00517   foreach (OutputPair output_pair, output_data_)
00518   {
00519     //Replace the input with the output for this pair
00520     if (! replaceOriginalWithNew (output_pair.input_items_, output_pair.output_items_))
00521       qCritical () << "Removal of items failed in DeleteItemCommand::redo";
00522   
00523   }
00524 }
00525 
00526 
00529 
00530 pcl::cloud_composer::MergeCloudCommand::MergeCloudCommand (ConstItemList input_data, QUndoCommand* parent)
00531   : CloudCommand (input_data, parent)
00532 {
00533   
00534 }
00535 
00536 bool
00537 pcl::cloud_composer::MergeCloudCommand::runCommand (AbstractTool* tool)
00538 {
00539   //In merge command, input clouds will be combined, so send them to tool together
00540   QList <CloudComposerItem*> output_items;
00541   if (canUseTemplates(original_data_))
00542     output_items = tool->performAction (original_data_, static_cast<PointTypeFlags::PointType> (template_type_));
00543   else
00544     output_items = tool->performAction (original_data_);
00545   MergeSelection* merge_selection = dynamic_cast <MergeSelection*> (tool);
00546   // If this is a merge selection we need to put the partially selected items into the original data list too!
00547   // We didn't send them before because merge selection already knows about them (and needs to tree input list differently from selected items)
00548   if (merge_selection)
00549   {
00550     QList <const CloudItem*> selected_items = merge_selection->getSelectedItems();
00551     foreach (const CloudItem* item, selected_items)
00552       original_data_.append (item);
00553   }
00554   OutputPair output_pair = {original_data_, output_items};
00555   output_data_.append (output_pair);
00556   
00557   if (output_items.size () == 0)
00558   {
00559     qWarning () << "Warning: Tool " << tool->getToolName () << "returned no item in a MergeCloudCommand";
00560     return false;
00561   }
00562   
00563   this->setText ("Merge Clouds");
00564   return true;
00565 }
00567 
00568 void
00569 pcl::cloud_composer::MergeCloudCommand::undo ()
00570 {
00571   last_was_undo_ = true;
00572   //Add the original items back into the model
00573   foreach (OutputPair output_pair, output_data_)
00574   {
00575     if (!restoreOriginalRemoveNew (output_pair.input_items_, output_pair.output_items_))
00576       qCritical () << "Failed to restore original clouds in MergeCloudCommand::undo!";
00577   }
00578 }
00580 
00581 void
00582 pcl::cloud_composer::MergeCloudCommand::redo ()
00583 {
00584   qDebug () << "Redo in MergeCloudCommand ";
00585   last_was_undo_ = false;
00586   //There is only one output_pair, but thats ok
00587   foreach (OutputPair output_pair, output_data_)
00588   {
00589     //Replace the input with the output for this pair
00590     // This works because all input clouds must have same parent, the root item (clouds must be on top level)
00591     if (! replaceOriginalWithNew (output_pair.input_items_, output_pair.output_items_))
00592       qCritical () << "Removal of items failed in MergeCloudCommand::redo";
00593   
00594   }
00595 }


pcl
Author(s): Open Perception
autogenerated on Wed Aug 26 2015 15:22:49