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
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
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
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
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
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00116
00117 bool
00118 pcl::cloud_composer::CloudCommand::replaceOriginalWithNew (QList <const CloudComposerItem*> originals, QList <CloudComposerItem*> new_items)
00119 {
00120
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
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
00138 if (parent_item == 0)
00139 parent_item = project_model_->invisibleRootItem ();
00140
00141
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
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
00168 foreach (CloudComposerItem* item, new_items)
00169 {
00170 QStandardItem* parent_item = item->parent ();
00171
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
00181 QList <QStandardItem*> removed = parent_item->takeRow (to_remove_index.row ());
00182 }
00183
00184 QMap <QStandardItem*, QStandardItem*>::iterator itr;
00185 foreach (const CloudComposerItem* item, originals)
00186 {
00187
00188
00189
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
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
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
00296
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
00339 const CloudComposerItem* const_input_item = output_pair.input_items_.value (0);
00340 QList <CloudComposerItem*> output_items = output_pair.output_items_;
00341
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
00349 QStandardItem* item_to_change = project_model_->itemFromIndex (input_index);
00350
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
00369 const CloudComposerItem* const_input_item = output_pair.input_items_.value (0);
00370 QList <CloudComposerItem*> output_items = output_pair.output_items_;
00371
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
00379 QStandardItem* input_item = (project_model_->itemFromIndex (input_index));
00380
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
00403
00404 int num_new_items = 0;
00405 foreach (const CloudComposerItem *item, original_data_)
00406 {
00407
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
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
00482
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
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
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
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
00547
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
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
00587 foreach (OutputPair output_pair, output_data_)
00588 {
00589
00590
00591 if (! replaceOriginalWithNew (output_pair.input_items_, output_pair.output_items_))
00592 qCritical () << "Removal of items failed in MergeCloudCommand::redo";
00593
00594 }
00595 }