NCBI C++ ToolKit
macro_fn_aecr.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: macro_fn_aecr.cpp 47378 2023-02-27 20:09:44Z asztalos $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Andrea Asztalos
27  *
28  */
29 
30 #include <ncbi_pch.hpp>
36 #include <objects/seq/Seqdesc.hpp>
37 
42 #include <util/xregexp/regexp.hpp>
43 #include <objmgr/util/sequence.hpp>
44 
47 
53 
59 
60 /** @addtogroup GUI_MACRO_SCRIPTS_UTIL
61  *
62  * @{
63  */
64 
66 BEGIN_SCOPE(macro)
68 
69 // All DO functions should make changes on the "Edited" object of the BioDataIterator
70 
71 /// class CMacroFunction_SwapRelatedFeaturesQual_Depr
72 /// SwapRelateFeaturesQual(src_field, dest_feat_subtype, dest_field);
73 ///
74 DEFINE_MACRO_FUNCNAME(CMacroFunction_SwapRelatedFeaturesQual_Depr, "SwapRelateFeaturesQual")
75 void CMacroFunction_SwapRelatedFeaturesQual_Depr::TheFunction()
76 {
77  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
78  const CSeq_feat* src_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
79  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
80  if (!src_feat || !scope)
81  return;
82 
83  CObjectInfo oi = m_DataIter->GetEditedObject();
84 
85  CMQueryNodeValue::TObs src_objs;
86  CMQueryNodeValue::EType src_type = m_Args[0]->GetDataType();
87 
88  // the source field has to be set
89  if (src_type == CMQueryNodeValue::eString) {
90  if (!GetFieldsByName(&src_objs, oi, m_Args[0]->GetString()))
91  return;
92  }
93  else if (src_type == CMQueryNodeValue::eObjects) {
94  src_objs = m_Args[0]->GetObjects();
95  }
96  else if (src_type == CMQueryNodeValue::eRef) {
97  x_GetObjectsFromRef(src_objs, 0);
98  }
99 
100  if (src_objs.empty()) {
101  return;
102  }
103 
104  // the destination field also has to be set and
105  // should be a field from the corresponding feature
106  CSeqFeatData::ESubtype related_feature = NMacroUtil::GetFeatSubtype(m_Args[1]->GetString());
107  NMacroUtil::TVecFeatList feat_list = edit::GetRelatedFeatures(*src_feat, related_feature, scope);
108  if (feat_list.empty()) {
109  return;
110  }
111 
112  CConstRef<CSeq_feat> orig_feat = *feat_list.begin();
113  CRef<CSeq_feat> new_feat(new CSeq_feat);
114  new_feat->Assign(*orig_feat);
115  CObjectInfo objInfo(new_feat.GetPointer(), new_feat.GetPointer()->GetTypeInfo());
116 
117  CMQueryNodeValue::TObs dest_objs;
118  const string& dest_field = m_Args[2]->GetString();
119  if (!GetFieldsByName(&dest_objs, objInfo, dest_field) || dest_objs.empty()) {
120  return;
121  }
122 
123  CMQueryNodeValue::TObs::iterator src_it = src_objs.begin();
124  CMQueryNodeValue::TObs::iterator dest_it = dest_objs.begin();
125 
126  while (src_it != src_objs.end() && dest_it != dest_objs.end()) {
127  CObjectInfo src_prim = NMacroUtil::GetPrimitiveObjInfo(src_it->field);
128  CObjectInfo dest_prim = NMacroUtil::GetPrimitiveObjInfo(dest_it->field);
129  if (CMacroFunction_SwapQual::s_SwapFields(src_prim, dest_prim)) {
130  m_QualsChangedCount += 2;
131  }
132  ++src_it;
133  ++dest_it;
134  }
135 
136  if (m_QualsChangedCount) {
137  m_DataIter->SetModified();
138 
139  CRef<CCmdComposite> cmd(new CCmdComposite("Change Related feature"));
140  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(scope->GetSeq_featHandle(*orig_feat), *new_feat)));
141  m_DataIter->RunCommand(cmd, m_CmdComposite);
142 
143  TChangedQuals report;
144  report["swapping qualifiers"] = m_QualsChangedCount;
145  CRef<IFunctionLog> fnc_log(new CGeneralFuncLog(report));
146  x_LogChangedQuals(fnc_log);
147  }
148 }
149 
150 bool CMacroFunction_SwapRelatedFeaturesQual_Depr::x_ValidArguments() const
151 {
152  if (m_Args.size() != 3) {
153  return false;
154  }
155 
156  if (!(m_Args[0]->IsString() || m_Args[0]->AreObjects() || m_Args[0]->IsRef()))
157  return false;
158 
159  for (size_t index = 1; index < m_Args.size(); ++index) {
160  if (m_Args[index]->GetDataType() != CMQueryNodeValue::eString) {
161  return false;
162  }
163  }
164 
165  return true;
166 }
167 
168 
169 ///////////////////////////////////////////////////////////////////////////////
170 /// class CMacroFunction_RemoveQual
171 /// RemoveQual("genome");
172 /// or
173 /// obj = PUB_AFFIL("sub");
174 /// RemoveQual(obj);
175 ///
177 
178 void CMacroFunction_RemoveQual::TheFunction()
179 {
180  CMQueryNodeValue::EType type = m_Args[0]->GetDataType();
181 
182  CObjectInfo oi = m_DataIter->GetEditedObject();
183  CMQueryNodeValue::TObs res_oi;
185  const string& field_name = m_Args[0]->GetString();
186  if (!GetFieldsByName(&res_oi, oi, field_name))
187  return;
188  }
189  else if (type == CMQueryNodeValue::eObjects) {
190  res_oi = m_Args[0]->GetObjects();
191  }
192  else if (type == CMQueryNodeValue::eRef) {
193  x_GetObjectsFromRef(res_oi, 0);
194  }
195 
196  if (res_oi.empty()) {
197  return;
198  }
199 
200  m_QualsChangedCount = s_RemoveFields(m_DataIter, res_oi);
201 
202  if (m_QualsChangedCount) {
203  TChangedQuals report;
204  report["removal of qualifiers"] = m_QualsChangedCount;
205  CRef<IFunctionLog> fnc_log(new CGeneralFuncLog(report));
206  x_LogChangedQuals(fnc_log);
207  }
208 }
209 
211 {
212  if (m_Args.empty()) return false;
213  bool first_ok = (m_Args[0]->IsString() || m_Args[0]->AreObjects() || m_Args[0]->IsRef());
214  return (m_Args.size() == 1 && first_ok);
215 }
216 
218 {
219  if (objs.empty())
220  return 0;
221 
222  Int4 quals_changed = 0;
223  CObjectInfo oi = dataiter->GetEditedObject();
224 
225  // special attention to gene qualifiers that are removed from gene Xrefs
226  bool is_gene_suppressed_before = false;
227  bool is_gene_suppressed_after = false;
228  CConstRef<CObject> obj = dataiter->GetScopedObject().object;
229  if (dynamic_cast<const CSeq_feat*>(obj.GetPointer())) {
231  auto gene_xref = feat->GetGeneXref();
232  is_gene_suppressed_before = gene_xref && gene_xref->IsSuppressed();
233  }
234 
235  bool is_taxname = NMacroUtil::IsTaxname(objs.front());
237  if (NStr::EqualNocase(it->parent.GetName(), "Name-std")) {
238  CObjectInfoMI mem = it->parent.FindClassMember("first");
239  if (mem.IsSet() && mem.GetMember() == it->field) {
240  CName_std* std_name = CTypeConverter<CName_std>::SafeCast(it->parent.GetObjectPtr());
241  NMacroUtil::RemoveFirstName(*std_name);
242  quals_changed++;
243  }
244  else {
245  if (RemoveFieldByName(*it)) {
246  quals_changed++;
247  }
248  }
249  }
250  else {
251  if (RemoveFieldByName(*it)) {
252  quals_changed++;
253  }
254  }
255  }
256 
257  if (quals_changed) {
258  if (is_taxname) {
260  }
261  CConstRef<CObject> obj = dataiter->GetScopedObject().object;
262  CRef<CScope> scope = dataiter->GetScopedObject().scope;
263 
264  if (dynamic_cast<const CUser_object*>(obj.GetPointer())) {
266  if (userobj->IsSetData() && userobj->GetData().empty()) {
267  dataiter->SetToDelete(true);
268  }
269  else if (userobj->GetType().IsStr() && NStr::EqualCase(userobj->GetType().GetStr(), "DBLink")) {
270  EDIT_EACH_USERFIELD_ON_USEROBJECT(field_it, *userobj) {
271  CUser_field& field = **field_it;
272  if (field.IsSetData()) {
273  if ((field.GetData().IsStrs() && field.GetData().GetStrs().empty()) ||
274  (field.GetData().IsStr() && field.GetData().GetStr().empty())) {
275  ERASE_USERFIELD_ON_USEROBJECT(field_it, *userobj);
276  }
277  }
278  }
279  }
280  }
281  else if (dynamic_cast<const CSeqdesc*>(obj.GetPointer())) {
283  if (desc->IsGenbank() && desc->GetGenbank().IsEmpty()) {
284  dataiter->SetToDelete(true);
285  }
286  }
287  else if (dynamic_cast<const CBioseq*>(obj.GetPointer())) {
290  } else {
292  if (dynamic_cast<const CSeq_feat*>(obj.GetPointer())) {
294  cleanup.BasicCleanup(*seq_feat);
295  if (seq_feat->IsSetXref()) {
296  auto gene_xref = seq_feat->GetGeneXref();
297  if (gene_xref) {
298  is_gene_suppressed_after = gene_xref->IsSuppressed();
299  if (!is_gene_suppressed_before && is_gene_suppressed_after)
300  NMacroUtil::RemoveGeneXref(*seq_feat);
301  }
302  }
303  }
304  else if (dynamic_cast<const CBioSource*>(obj.GetPointer())) {
306  cleanup.BasicCleanup(*bsrc);
307  if (bsrc->IsSetOrg() && bsrc->GetOrg().IsSetDb() && bsrc->GetOrg().GetDb().empty()) {
308  bsrc->SetOrg().ResetDb();
309  }
310  }
311  }
312 
313  dataiter->SetModified();
314  }
315  return quals_changed;
316 }
317 
318 
319 // cleanup for biosource
321 {
322  if (bsrc.IsSetOrgMod()) {
323  if (bsrc.GetOrg().GetOrgname().GetMod().empty()) {
324  bsrc.SetOrg().SetOrgname().ResetMod();
325  }
326  }
327 
328  if (bsrc.IsSetSubtype()) {
329  if (bsrc.GetSubtype().empty()) {
330  bsrc.ResetSubtype();
331  }
332  }
333 }
334 
335 ///////////////////////////////////////////////////////////////////////////////
336 /// class CMacroFunction_RemoveModifier
337 /// o = Resolve(path_to_container) Where o.subtype = subtype;
338 /// RemoveModifier(o) - deleting subtype modifier from the list of modifiers
339 ///
340 DEFINE_MACRO_FUNCNAME(CMacroFunction_RemoveModifier, "RemoveModifier")
341 
342 void CMacroFunction_RemoveModifier::TheFunction()
343 {
344  // objects to be removed:
345  CMQueryNodeValue::TObs res_oi;
346  x_GetObjectsFromRef(res_oi, 0);
347  if (res_oi.empty()) {
348  // nothing to delete
349  return;
350  }
351 
352  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
353  const CBioSource* c_bsrc = dynamic_cast<const CBioSource*>(obj.GetPointer());
354  // the asn selector should be a biosource
355  if (!c_bsrc) {
356  return;
357  }
358 
360  if (RemoveFieldByName(*it)) {
361  m_QualsChangedCount++;
362  }
363  }
364 
365  if (m_QualsChangedCount) {
366  CObjectInfo oi = m_DataIter->GetEditedObject();
368  s_ResetModSubsrcQuals(*bsrc);
369  m_DataIter->SetModified();
370 
371  TChangedQuals report;
372  report["removing source modifiers"] = m_QualsChangedCount;
373  CRef<IFunctionLog> fnc_log(new CGeneralFuncLog(report));
374  x_LogChangedQuals(fnc_log);
375  }
376 }
377 
378 bool CMacroFunction_RemoveModifier::x_ValidArguments() const
379 {
380  return (m_Args.size() == 1 && m_Args[0]->GetDataType() == CMQueryNodeValue::eRef);
381 }
382 
383 
384 ///////////////////////////////////////////////////////////////////////////////
385 // class CMacroFunction_RemoveOutside
386 /// RemoveOutsideStringQual(field_name(str/obj), before_match(b), left_del(str), rmv_left(b),
387 /// after_match(b), right_del(str), rmv_right(b), case_insensitive(b), whole_word(b), update_mrna(b))
388 /// Last parameter is optional
389 ///
390 DEFINE_MACRO_FUNCNAME(CMacroFunction_RemoveOutside, "RemoveOutsideStringQual")
391 
392 void CMacroFunction_RemoveOutside::TheFunction()
393 {
394  CObjectInfo oi = m_DataIter->GetEditedObject();
395  CMQueryNodeValue::TObs res_oi;
396  CMQueryNodeValue::EType type = m_Args[0]->GetDataType();
397 
399  if (!GetFieldsByName(&res_oi, oi, m_Args[0]->GetString()))
400  return;
401  }
402  else if (type == CMQueryNodeValue::eObjects) {
403  res_oi = m_Args[0]->GetObjects();
404  }
405  else if (type == CMQueryNodeValue::eRef) {
406  x_GetObjectsFromRef(res_oi, 0);
408  }
409 
410  if (res_oi.empty()) {
411  return;
412  }
413 
414 
415  CRef<CRemoveTextOptions> options = x_GetRemoveTextOptions(1);
416  x_RmvOutsideFields(res_oi, *options);
417 
418  if (m_QualsChangedCount) {
419  NMacroUtil::CleanupForTaxnameChange(res_oi.front(), oi);
420  m_DataIter->SetModified();
421 
423  log << m_DataIter->GetBestDescr() << ": removed text outside string in " << m_QualsChangedCount << " qualifiers";
424 
425  bool update_mrna = (m_Args.size() == 10) ? m_Args[9]->GetBool() : false;
426  CConstRef<CObject> object = m_DataIter->GetScopedObject().object;
427  const CSeq_feat* feat = dynamic_cast<const CSeq_feat*>(object.GetPointer());
428 
429  if (update_mrna && feat && feat->GetData().GetSubtype() == CSeqFeatData::eSubtype_prot) {
430  string message;
431  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
433  string prot_product = edit_feat->GetData().GetProt().GetName().front();
434  CRef<CCmdComposite> cmd = UpdatemRNAProduct(prot_product, object, *scope);
435  if (cmd) {
436  m_DataIter->RunCommand(cmd, m_CmdComposite);
437  log << ", applied " + prot_product + " to mRNA product name ";
438  }
439  }
440  x_LogFunction(log);
441  }
442 }
443 
445 {
447  string left_del = m_Args[start_index + 1]->GetString();
448  bool remove_before_match = false;
449  if (m_Args[start_index]->GetBool()) {
450  if (NStr::EqualCase(left_del, "eDigits")) {
451  before_match = CRemoveTextOptions::eDigits;
452  left_del = kEmptyStr;
453  }
454  else if (NStr::EqualCase(left_del, "eLetters")) {
455  before_match = CRemoveTextOptions::eLetters;
456  left_del = kEmptyStr;
457  }
458  else {
459  before_match = CRemoveTextOptions::eText;
460  }
461  remove_before_match = m_Args[start_index + 2]->GetBool();
462  }
463 
464 
466  string right_del = m_Args[start_index + 4]->GetString();
467  bool remove_after_match = false;
468  if (m_Args[start_index + 3]->GetBool()) {
469  if (NStr::EqualCase(right_del, "eDigits")) {
470  after_match = CRemoveTextOptions::eDigits;
471  right_del = kEmptyStr;
472  }
473  else if (NStr::EqualCase(right_del, "eLetters")) {
474  after_match = CRemoveTextOptions::eLetters;
475  right_del = kEmptyStr;
476  }
477  else {
478  after_match = CRemoveTextOptions::eText;
479  }
480  remove_after_match = m_Args[start_index + 5]->GetBool();
481  }
482 
483  bool case_insensitive = m_Args[start_index + 6]->GetBool();
484  bool whole_word = m_Args[start_index + 7]->GetBool();
485 
486  CRef<CRemoveTextOptions> options(new CRemoveTextOptions(before_match, left_del, remove_before_match,
487  after_match, right_del, remove_after_match,
488  case_insensitive, whole_word));
489  return options;
490 }
491 
493 {
494  for (auto& it : resolved_objs) {
497  for (auto& iter : objs) {
498  CObjectInfo obj_oi = iter.field;
500  string value = obj_oi.GetPrimitiveValueString();
501  if (options.EditText(value)) {
502  SetQualStringValue(obj_oi, value);
503  }
504  }
505  else if (obj_oi.GetPrimitiveValueType() == ePrimitiveValueEnum) {
506  string value;
507  try {
508  value = obj_oi.GetPrimitiveValueString();
509  }
510  catch (const CException&) {
512  }
513  if (options.EditText(value)) {
514  try {
517  }
518  catch (const CException&) {
519  // if this fails, try to convert the string to int and assign again
520  try {
524  }
525  catch (const CException&) {}
526  }
527  }
528  }
529  }
530  }
531 }
532 
534 {
535  if (m_Args.size() != 9 && m_Args.size() != 10)
536  return false;
537 
538  CMQueryNodeValue::EType type = m_Args[0]->GetDataType();
540  if (!first_ok)
541  return false;
542 
543  return x_CheckArguments(1);
544 }
545 
547 {
548  if (m_Args[index]->GetDataType() != CMQueryNodeValue::eBool
549  || m_Args[++index]->GetDataType() != CMQueryNodeValue::eString
550  || m_Args[++index]->GetDataType() != CMQueryNodeValue::eBool) {
551  return false;
552  }
553  if (m_Args[++index]->GetDataType() != CMQueryNodeValue::eBool
554  || m_Args[++index]->GetDataType() != CMQueryNodeValue::eString
555  || m_Args[++index]->GetDataType() != CMQueryNodeValue::eBool) {
556  return false;
557  }
558  ++index;
559  for (size_t i = index; i < m_Args.size(); ++i) {
560  if (m_Args[i]->GetDataType() != CMQueryNodeValue::eBool)
561  return false;
562  }
563  return true;
564 }
565 
566 ///////////////////////////////////////////////////////////////////////////////
567 /// class CMacroFunction_SetStringQual
568 /// Expected Syntax:
569 /// SetStringQual(field_name, newValue, existingtext_option, delimiter, remove_blank)
570 /// The last two parameters are optional.
571 /// Empty new values don't have any effect by default. If remove_blank is True,
572 /// the existing field is removed.
573 ///
575 
576 void CMacroFunction_SetStringQual::TheFunction()
577 {
578  size_t index = 1;
579  string newValue = NMacroUtil::GetStringValue(m_Args[index]);
580  const string& action_type = m_Args[++index]->GetString();
581  string delimiter;
582  bool remove_field = false;
583  x_GetOptionalArgs(delimiter, remove_field, index);
584 
585  CObjectInfo oi = m_DataIter->GetEditedObject();
586  CMQueryNodeValue::TObs res_oi;
587  CMQueryNodeValue::EType type = m_Args[0]->GetDataType();
588 
590  if (remove_field && newValue.empty()) {
591  if (!GetFieldsByName(&res_oi, oi, m_Args[0]->GetString()))
592  return;
593  }
594  else if (!newValue.empty() && !SetFieldsByName(&res_oi, oi, m_Args[0]->GetString())) {
595  return;
596  }
597  }
598  else if (type == CMQueryNodeValue::eObjects) {
599  res_oi = m_Args[0]->GetObjects();
600  }
601  else if (type == CMQueryNodeValue::eRef) {
602  x_GetObjectsFromRef(res_oi, 0);
603  }
604 
605  if (res_oi.empty()) {
606  return;
607  }
608 
609  if (!newValue.empty()) {
610  vector<string> new_values;
612  x_SetFields(res_oi, newValue, existing_text, new_values);
613 
614  m_Result->SetBool(false);
615  if (m_QualsChangedCount) {
616  NMacroUtil::CleanupForTaxnameChange(res_oi.front(), oi);
617  m_DataIter->SetModified();
618  m_Result->SetBool(true);
619 
621  for (size_t i = 0; i < new_values.size(); ++i) {
622  log << m_DataIter->GetBestDescr() << ": set '" << new_values[i] << "' as a new value\n";
623  }
624  x_LogFunction(log);
625  }
626  }
627  else if (remove_field) {
628  m_QualsChangedCount = CMacroFunction_RemoveQual::s_RemoveFields(m_DataIter, res_oi);
629  if (m_QualsChangedCount) {
631  log << m_DataIter->GetBestDescr() << ": removed " << m_QualsChangedCount << " qualifiers";
632  x_LogFunction(log);
633  }
634  }
635 }
636 
638 {
639  // can accept as its first parameter: objects, string or reference
640  size_t arg_nr = m_Args.size();
641  if (arg_nr < 3 && arg_nr > 5) {
642  return false;
643  }
644 
645  size_t index = 0;
646  bool first_ok = m_Args[index]->IsString() || m_Args[index]->AreObjects() || m_Args[index]->IsRef();
647  if (!first_ok) return false;
648 
649  ++index;
650  NMacroUtil::GetPrimitiveFromRef(m_Args[index].GetNCObject());
651  bool second_ok = m_Args[index]->IsString() || m_Args[index]->IsInt() || m_Args[index]->IsDouble();
652  if (!second_ok) return false;
653 
654  if (!m_Args[++index]->IsString()) return false;
655 
656  if (arg_nr > 3 && (!m_Args[++index]->IsString() && !m_Args[index]->IsBool())) return false;
657 
658  if (arg_nr > 4 && !m_Args[++index]->IsBool()) return false;
659 
660  return true;
661 }
662 
664  edit::EExistingText existing_text, vector<string>& new_values)
665 {
666  for (auto& it : objs) {
667  CObjectInfo obj = it.field;
668  switch (obj.GetTypeFamily()) {
669  case eTypeFamilyPrimitive: // works when the field exists or does not
670  if (existing_text != edit::eExistingText_add_qual) {
671  x_SetNewPrimitiveValue(obj, newValue, existing_text, new_values);
672  }
673  else if (it.parent.GetTypeFamily() == eTypeFamilyContainer) {
674  // add new element to the container
675  CObjectInfo new_oi(it.parent.AddNewElement());
676  SetQualStringValue(new_oi, newValue);
677  new_values.push_back(newValue);
678  }
679  break;
680  case eTypeFamilyPointer: // works only when the field exists
682  CObjectInfo oi_ptr(obj.GetPointedObject());
683  x_SetNewPrimitiveValue(oi_ptr, newValue, existing_text, new_values);
684  }
685  break;
686  case eTypeFamilyContainer: { // works when the field exists or does not
689 
690  if (objs.empty() || existing_text == edit::eExistingText_add_qual) {
692  CObjectInfo new_oi(obj.AddNewPointedElement());
693  SetQualStringValue(new_oi, newValue);
694  new_values.push_back(newValue);
695  }
696  else {
697  CObjectInfo new_oi(obj.AddNewElement());
698  SetQualStringValue(new_oi, newValue);
699  new_values.push_back(newValue);
700  }
701  }
702  else {
703  if (existing_text == edit::eExistingText_replace_old) {
704  if (objs.size() > 1) {
705  // keep the first element, update it and delete the rest from the container
707  CObjectInfoEI e = first;
708  ++e;
709  while (e) {
710  e.Erase();
711  e = first;
712  ++e;
713  }
714  }
715  SetQualStringValue(objs.front().field, newValue);
716  new_values.push_back(newValue);
717  }
718  else {
719  // there are multiple ones, and all of them needs to be updated
721  x_SetNewPrimitiveValue(iter->field, newValue, existing_text, new_values);
722  }
723  }
724  }
725  break;
726  }
727  default:
728  break;
729  }
730  }
731 }
732 
734  const string& newValue, edit::EExistingText existing_text, vector<string>& new_values)
735 {
737 
740 
741  string orig_value = oi.GetPrimitiveValueString();
742  if (edit::AddValueToString(orig_value, newValue, existing_text)) {
743  if (SetQualStringValue(oi, orig_value)) {
744  new_values.push_back(orig_value);
745  }
746  }
747  }
748 }
749 
750 ///////////////////////////////////////////////////////////////////////////////
751 ///class CMacroFunction_SetRnaProduct
752 /// SetRnaProduct(new_value, existing_text_opt, delimiter, remove_blank)
753 ///
754 DEFINE_MACRO_FUNCNAME(CMacroFunction_SetRnaProduct, "SetRnaProduct")
755 void CMacroFunction_SetRnaProduct::TheFunction()
756 {
757  CConstRef<CObject> object = m_DataIter->GetScopedObject().object;
758  const CSeq_feat* seq_feat = dynamic_cast<const CSeq_feat*>(object.GetPointer());
759  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
760  if (!seq_feat || !seq_feat->GetData().IsRna() || !scope)
761  return;
762 
763  size_t index = 0;
764  string newValue = NMacroUtil::GetStringValue(m_Args[index]);
765  const string& action_type = m_Args[++index]->GetString();
766  string delimiter;
767  bool remove_field = false;
768  x_GetOptionalArgs(delimiter, remove_field, index);
769 
770  CObjectInfo oi = m_DataIter->GetEditedObject();
773 
774  CRNA_ref& rna_ref = edit_feat->SetData().SetRna();
775  string orig_value = rna_ref.GetRnaProductName();
776 
777  if (!newValue.empty()) {
778  string remainder;
779  if (edit::AddValueToString(orig_value, newValue, existing_text)) {
780  rna_ref.SetRnaProductName(orig_value, remainder);
781  m_QualsChangedCount++;
782  if (!remainder.empty()) {
783  if (edit_feat->IsSetComment()) {
784  existing_text = edit::eExistingText_append_semi;
785  edit::AddValueToString(edit_feat->SetComment(), remainder, existing_text);
786  }
787  }
788  }
789  }
790  else if (remove_field) {
791  string remainder;
792  rna_ref.SetRnaProductName(kEmptyStr, remainder);
793  m_QualsChangedCount++;
794  }
795 
796  if (m_QualsChangedCount) {
797  m_DataIter->SetModified();
798 
800  log << m_DataIter->GetBestDescr();
801  if (newValue.empty() && remove_field) {
802  log << ": removed rna product";
803  }
804  else {
805  log << ": set '" << orig_value << "' as new rna product value";
806  }
807  x_LogFunction(log);
808  }
809 }
810 
811 bool CMacroFunction_SetRnaProduct::x_ValidArguments() const
812 {
813  // can accept as its first parameter: objects, string or reference
814  size_t arg_nr = m_Args.size();
815  if (arg_nr < 2 && arg_nr > 4) {
816  return false;
817  }
818 
819  size_t index = 0;
820  NMacroUtil::GetPrimitiveFromRef(m_Args[index].GetNCObject());
821  bool first_ok = m_Args[index]->IsString() || m_Args[index]->IsInt() || m_Args[index]->IsDouble();
822  if (!first_ok) return false;
823 
824  if (!m_Args[++index]->IsString()) return false;
825  if (arg_nr > 2 && (!m_Args[++index]->IsString() && !m_Args[index]->IsBool())) return false;
826  if (arg_nr > 3 && !m_Args[++index]->IsBool()) return false;
827 
828  return true;
829 }
830 
831 
832 ///////////////////////////////////////////////////////////////////////////////
833 /// class CMacroFunction_GetRnaProduct
834 /// GetRnaProduct()
835 ///
836 DEFINE_MACRO_FUNCNAME(CMacroFunction_GetRnaProduct, "GETRNAPRODUCT")
837 
838 void CMacroFunction_GetRnaProduct::TheFunction()
839 {
840  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
841  const CSeq_feat* feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
842  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
843  m_Result->SetNotSet();
844  if (!feat || !scope || !(feat->IsSetData() && feat->GetData().IsRna()))
845  return;
846 
847  const CRNA_ref& rna_ref = feat->GetData().GetRna();
848  string value = rna_ref.GetRnaProductName();
849 
850  if (m_Nested == eNotNested) { // return a string
851  m_Result->SetString(value);
852  }
853  else {
854  // return a reference to a CMQueryNodeValue of type string
856  new_node->SetString(value);
857  m_Result->SetRef(new_node);
858  }
859 }
860 
861 bool CMacroFunction_GetRnaProduct::x_ValidArguments() const
862 {
863  return (m_Args.empty());
864 }
865 ///////////////////////////////////////////////////////////////////////////////
866 /// class CMacroFunction_RemoveRnaProduct
867 /// RemoveRnaProduct()
868 ///
869 DEFINE_MACRO_FUNCNAME(CMacroFunction_RemoveRnaProduct, "RemoveRnaProduct")
870 void CMacroFunction_RemoveRnaProduct::TheFunction()
871 {
872  CObjectInfo oi = m_DataIter->GetEditedObject();
874  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
875  if (!edit_feat || !edit_feat->GetData().IsRna() || !scope)
876  return;
877 
878  CRNA_ref& rna_ref = edit_feat->SetData().SetRna();
879  string remainder;
880  rna_ref.SetRnaProductName(kEmptyStr, remainder);
881 
882  m_DataIter->SetModified();
883  m_QualsChangedCount++;
884 
885  TChangedQuals report;
886  report["removing RNA product"] = m_QualsChangedCount;
887  CRef<IFunctionLog> fnc_log(new CGeneralFuncLog(report));
888  x_LogChangedQuals(fnc_log);
889 }
890 
891 bool CMacroFunction_RemoveRnaProduct::x_ValidArguments() const
892 {
893  return (m_Args.empty());
894 }
895 
896 
897 ///////////////////////////////////////////////////////////////////////////////
898 /// class CMacroFunction_EditStringQual
899 /// Usage: EditStringQual(field_name|rt_obj, find_text, repl_text, location, case_sensitive, is_regex)
900 ///
902 
903 void CMacroFunction_EditStringQual::TheFunction()
904 {
905  size_t index = 1;
906  const string& find_txt = NMacroUtil::GetStringValue(m_Args[index]);
907  string repl_txt = NMacroUtil::GetStringValue(m_Args[++index]);
908  const string& location = m_Args[++index]->GetString();
909  bool case_sensitive = m_Args[++index]->GetBool();
910  bool is_regex = (++index < m_Args.size()) ? m_Args[index]->GetBool() : false;
911 
912  m_Result->SetBool(false); // assume, that no change has been made
913 
914  CObjectInfo oi = m_DataIter->GetEditedObject();
915  CMQueryNodeValue::TObs res_oi;
916  CMQueryNodeValue::EType type = m_Args[0]->GetDataType();
917 
919  if (!GetFieldsByName(&res_oi, oi, m_Args[0]->GetString()))
920  return;
921  }
922  else if (type == CMQueryNodeValue::eObjects) {
923  res_oi = m_Args[0]->GetObjects();
924  }
925  else if (type == CMQueryNodeValue::eRef) {
926  x_GetObjectsFromRef(res_oi, 0);
928  }
929 
930  if (res_oi.empty()) {
931  return;
932  }
933 
934  x_EditFields(res_oi, find_txt, repl_txt, s_GetLocFromName(location), case_sensitive, is_regex);
935  if (m_QualsChangedCount) {
936  NMacroUtil::CleanupForTaxnameChange(res_oi.front(), oi);
937 
938  m_DataIter->SetModified();
939  m_Result->SetBool(true); // the field has been modified
940 
942  log << m_DataIter->GetBestDescr() << ": edited " << m_QualsChangedCount << " qualifiers, replaced " << find_txt;
943  if (NStr::IsBlank(repl_txt)) {
944  repl_txt.assign("''");
945  }
946  log << " with " << repl_txt;
947  x_LogFunction(log);
948  }
949 }
950 
951 bool CMacroFunction_EditStringQual::s_EditText(string& str, const string& find,
952  const string& replace, ESearchLoc loc, bool case_sensitive, bool is_regex)
953 {
954  bool rval = false;
955  if (is_regex)
956  {
958  if (case_sensitive)
959  {
960  options = CRegexp::fCompile_default;
961  }
962 
963  CRegexpUtil replacer(str);
964  size_t num = replacer.Replace(find, replace, options, CRegexp::fMatch_default, 0);
965  if (num > 0)
966  {
967  str = replacer.GetResult();
968  rval = true;
969  }
970  }
971  else
972  {
973  SIZE_TYPE pos = NPOS;
974  if (loc == eAnywhere) {
975  pos = NStr::Find(str, find, (case_sensitive) ? NStr::eCase : NStr::eNocase);
976  while (pos != NPOS) {
977  str = str.substr(0, pos) + replace + str.substr(pos + find.length());
978  if (case_sensitive) {
979  pos = NStr::FindCase(str, find, pos + replace.length());
980  }
981  else {
982  pos = NStr::FindNoCase(str, find, pos + replace.length());
983  }
984  rval = true;
985  }
986  }
987  else {
988  pos = NPOS;
989  if (loc == eBeginning) {
990  if (NStr::StartsWith(str, find, (case_sensitive) ? NStr::eCase : NStr::eNocase)) {
991  pos = 0;
992  }
993  }
994  else if (loc == eEnd) {
995  if (NStr::EndsWith(str, find, (case_sensitive) ? NStr::eCase : NStr::eNocase)) {
996  pos = str.length() - find.length();
997  }
998  }
999  if (pos != NPOS) {
1000  str = str.substr(0, pos) + replace + str.substr(pos + find.length());
1001  rval = true;
1002  }
1003  }
1004  }
1006 
1007  return rval;
1008 }
1009 
1011  CMQueryNodeValue::TObs& resolved_objs,
1012  const string& find_txt,
1013  const string& repl_txt,
1014  ESearchLoc loc,
1015  bool case_sensitive,
1016  bool is_regex)
1017 {
1018  for (auto& it : resolved_objs) {
1021  for(auto& iter : objs) {
1022  CObjectInfo oi = iter.field;
1024  string value = oi.GetPrimitiveValueString();
1025  if (s_EditText(value, find_txt, repl_txt, loc, case_sensitive, is_regex)) {
1026  if (NStr::EqualNocase(iter.parent.GetName(), "Name-std")) {
1027  CObjectInfoMI mem = iter.parent.FindClassMember("first");
1028  if (mem.IsSet() && mem.GetMember() == oi) {
1029  CName_std* std_name = CTypeConverter<CName_std>::SafeCast(iter.parent.GetObjectPtr());
1032  }
1034  }
1035  else {
1037  }
1038  }
1039  }
1040  else if (oi.GetPrimitiveValueType() == ePrimitiveValueInteger) {
1042  string orig_val = NStr::Int8ToString(value);
1043  if (s_EditText(orig_val, find_txt, repl_txt, loc, case_sensitive, is_regex)) {
1044  NStr::TruncateSpacesInPlace(orig_val);
1047  }
1048  }
1049 
1050  else if (oi.GetPrimitiveValueType() == ePrimitiveValueEnum) {
1051  string value;
1052  try {
1054  }
1055  catch (const CException&) {
1057  }
1058  if (s_EditText(value, find_txt, repl_txt, loc, case_sensitive, is_regex)) {
1059  try {
1062  }
1063  catch (const CException&) {
1064  // if this fails, try to convert the string to int and assign again
1065  try {
1068  }
1069  catch (const CException&) {}
1070  }
1071  }
1072  }
1073  }
1074  }
1075 }
1076 
1078 {
1079  ESearchLoc loc = eAnywhere; // default search location
1080  if (NStr::EqualNocase(name, "at the beginning")) {
1081  loc = eBeginning;
1082  }
1083  else if (NStr::EqualNocase(name, "at the end")) {
1084  loc = eEnd;
1085  }
1086  return loc;
1087 }
1088 
1090 {
1091  if (m_Args.size() != 5 && m_Args.size() != 6)
1092  return false;
1093 
1094  bool first_ok = m_Args[0]->IsString() || m_Args[0]->AreObjects() || m_Args[0]->IsRef();
1095  if (!first_ok) {
1096  return false;
1097  }
1098 
1099  for (size_t index = 1; index < 3; index++) {
1100  if (!m_Args[index]->IsString() && !m_Args[index]->IsInt()) {
1101  return false;
1102  }
1103  }
1104  if (m_Args.size() == 6) {
1105  if (!m_Args.back()->IsBool())
1106  return false;
1107  }
1108  return (m_Args[3]->IsString() && m_Args[4]->IsBool());
1109 }
1110 
1111 
1112 ///////////////////////////////////////////////////////////////////////////////
1113 namespace {
1114 
1115  vector<string> kSatelliteTypes = { "satellite", "microsatellite", "minisatellite" };
1116  vector<string> kMobileETypeTypes = {
1117  "insertion sequence",
1118  "integron",
1119  "LINE",
1120  "MITE",
1121  "non-LTR retrotransposon",
1122  "other",
1123  "P-element",
1124  "retrotransposon",
1125  "SINE",
1126  "superintegron",
1127  "transposable element",
1128  "transposon"
1129  };
1130  bool GetBioSourceDestObjects(CObjectInfo& oi, const string& field_name, CMQueryNodeValue::TObs& dest_objs);
1131 
1132  bool SetFeatDestinationField(CRef<CSeq_feat> feat, const string& field_name, CMQueryNodeValue::TObs& result);
1133 
1134  bool IstRNAProductField(const CSeq_feat& feat, const string& field_name);
1135 
1136  bool GetDestinationObjects(CConstRef<CObject> object, CObjectInfo& oi, const string& field_name, CMQueryNodeValue::TObs& result)
1137  {
1138  const CBioSource* bsrc = dynamic_cast<const CBioSource*>(object.GetPointer());
1139  const CSeq_feat* seq_feat = dynamic_cast<const CSeq_feat*>(object.GetPointer());
1140  if (bsrc) {
1141  return GetBioSourceDestObjects(oi, field_name, result);
1142  }
1143  if (seq_feat) {
1145  return SetFeatDestinationField(Ref(feat), field_name, result);
1146  }
1147 
1148  return SetFieldsByName(&result, oi, field_name);
1149  }
1150 
1151  bool GetBioSourceDestObjects(CObjectInfo& oi, const string& field_name, CMQueryNodeValue::TObs& dest_objs)
1152  {
1153  if (field_name.empty())
1154  return false;
1155 
1156  size_t orig_size = dest_objs.size();
1157  // check if the field denotes an orgmod or a subsource modifier
1158  if (NMacroUtil::IsBiosourceModifier(field_name)) {
1159 
1160  // extract it into a function that adds these modifier fields
1162  if (!bsrc)
1163  return false;
1164  // check if it's a subsource modifier
1167 
1168  EDIT_EACH_SUBSOURCE_ON_BIOSOURCE(subsrc, *bsrc) {
1169  if ((*subsrc)->IsSetSubtype() && (*subsrc)->GetSubtype() == st) {
1170  CObjectInfo subsrc_oi((*subsrc).GetPointer(), (*subsrc)->GetTypeInfo());
1171  CObjectInfo name_oi = subsrc_oi.FindClassMember("name").GetMember();
1172  dest_objs.push_back(CMQueryNodeValue::SResolvedField(subsrc_oi, name_oi));
1173  }
1174  }
1175 
1176  if (dest_objs.empty()) {
1177  CRef<CSubSource> sub_src(new CSubSource());
1178  sub_src->SetSubtype(st);
1179  bsrc->SetSubtype().push_back(sub_src);
1180  CObjectInfo subsrc_oi(sub_src.GetPointer(), sub_src->GetTypeInfo());
1181  CObjectInfo name_oi = subsrc_oi.FindClassMember("name").GetMember();
1182  dest_objs.push_back(CMQueryNodeValue::SResolvedField(subsrc_oi, name_oi));
1183  }
1184  // check if it's an orgmod modifier
1185  }
1188 
1189  EDIT_EACH_ORGMOD_ON_BIOSOURCE(orgmod, *bsrc) {
1190  if ((*orgmod)->IsSetSubtype() && (*orgmod)->GetSubtype() == st) {
1191  CObjectInfo orgmod_oi((*orgmod).GetPointer(), (*orgmod)->GetTypeInfo());
1192  CObjectInfo subname_oi = orgmod_oi.FindClassMember("subname").GetMember();
1193  dest_objs.push_back(CMQueryNodeValue::SResolvedField(orgmod_oi, subname_oi));
1194  }
1195  }
1196 
1197  if (dest_objs.empty()) {
1198  CRef<COrgMod> orgmod(new COrgMod());
1199  orgmod->SetSubtype(st);
1200  orgmod->SetSubname(kEmptyStr);
1201  if (!bsrc->IsSetOrgname()) {
1202  CRef<COrgName> orgname(new COrgName());
1203  orgname->SetMod().push_back(orgmod);
1204  bsrc->SetOrg().SetOrgname(*orgname);
1205  }
1206  else {
1207  bsrc->SetOrg().SetOrgname().SetMod().push_back(orgmod);
1208  }
1209  CObjectInfo orgmod_oi(orgmod.GetPointer(), orgmod->GetTypeInfo());
1210  CObjectInfo subname_oi = orgmod_oi.FindClassMember("subname").GetMember();
1211  dest_objs.push_back(CMQueryNodeValue::SResolvedField(orgmod_oi, subname_oi));
1212  }
1213  }
1214  }
1215  else {
1216  SetFieldsByName(&dest_objs, oi, field_name);
1217  }
1218 
1219  return dest_objs.size() - orig_size > 0;
1220  }
1221 
1222  // feature related functions
1223  bool SetFeatDestinationField(CRef<CSeq_feat> feat, const string& field_name, CMQueryNodeValue::TObs& result)
1224  {
1225  if (feat.IsNull() || field_name.empty())
1226  return false;
1227 
1228  CObjectInfo dest_oi(feat.GetPointer(), feat->GetThisTypeInfo());
1229  if (SetFieldsByName(&result, dest_oi, field_name)) {
1230  return true;
1231  }
1232 
1233  size_t orig_size = result.size();
1234  string field = field_name;
1235  if (NMacroUtil::IsSatelliteSubfield(field_name)) {
1236  field = "satellite";
1237  }
1238  else if (NMacroUtil::StringsAreEquivalent(field_name, "mobile-element-type-type")) {
1239  field = "mobile-element-type";
1240  }
1241 
1242  // field_name is a possible GB qualifier
1243  EDIT_EACH_GBQUAL_ON_SEQFEAT(gbq_it, *feat) {
1244  if ((*gbq_it)->IsSetQual() && NStr::EqualNocase((*gbq_it)->GetQual(), field)) {
1245  CObjectInfo gbqual_oi((*gbq_it).GetPointer(), (*gbq_it)->GetTypeInfo());
1246  CObjectInfo val_oi = gbqual_oi.FindClassMember("val").GetMember();
1247  result.push_back(CMQueryNodeValue::SResolvedField(gbqual_oi, val_oi));
1248  }
1249  }
1250 
1251  if (result.empty()) {
1252  if (NStr::EndsWith(field_name, "::product"))
1253  return true; // returning true but the output argument results is empty!
1254 
1255  CRef<CGb_qual> new_gbqual(new CGb_qual(field, kEmptyStr));
1256  feat->SetQual().push_back(new_gbqual);
1257  CObjectInfo gbqual_oi(new_gbqual.GetPointer(), new_gbqual->GetTypeInfo());
1258  CObjectInfo val_oi = gbqual_oi.FindClassMember("val").GetMember();
1259  result.push_back(CMQueryNodeValue::SResolvedField(gbqual_oi, val_oi));
1260  }
1261 
1262  return result.size() - orig_size > 0;
1263  }
1264 
1265  bool GetFeatDestinationField(CRef<CSeq_feat> feat, const string& field_name, CMQueryNodeValue::TObs& result)
1266  {
1267  if (field_name.empty())
1268  return false;
1269 
1270  CObjectInfo dest_oi(feat.GetPointer(), feat->GetThisTypeInfo());
1271  if (GetFieldsByName(&result, dest_oi, field_name)) {
1272  return true;
1273  }
1274 
1275  string field = field_name;
1276  if (NMacroUtil::IsSatelliteSubfield(field_name)) {
1277  field = "satellite";
1278  }
1279  else if (NMacroUtil::StringsAreEquivalent(field_name, "mobile-element-type-type")) {
1280  field = "mobile-element-type";
1281  }
1282 
1283  // field_name is a possible GB qualifier
1284  EDIT_EACH_GBQUAL_ON_SEQFEAT(gbq_it, *feat) {
1285  if ((*gbq_it)->IsSetQual() && NStr::EqualNocase((*gbq_it)->GetQual(), field)) {
1286  CObjectInfo gbqual_oi((*gbq_it).GetPointer(), (*gbq_it)->GetTypeInfo());
1287  CObjectInfo val_oi = gbqual_oi.FindClassMember("val").GetMember();
1288  result.push_back(CMQueryNodeValue::SResolvedField(gbqual_oi, val_oi));
1289  }
1290  }
1291  return (!result.empty());
1292  }
1293 
1294  bool IstRNAProductField(const CSeq_feat& feat, const string& field_name)
1295  {
1296  return (feat.IsSetData() &&
1298  (NStr::EqualNocase(field_name, "tRNA::product") || NStr::EqualNocase(field_name, "any::product")));
1299  }
1300 
1301  CRef<CSeq_feat> CreateNewGene(const CSeq_feat& src_feat, CScope& scope);
1302 
1303  CRef<CSeq_feat> CreateNewProtein(const CSeq_feat& src_feat, CScope& scope);
1304 
1305  CRef<CSeq_feat> CreateNewRelatedFeature(const CSeq_feat& src_feat, const string& field_name, CScope& scope)
1306  {
1307  if (NStr::EndsWith(field_name, "locus")) {
1308  return CreateNewGene(src_feat, scope);
1309  }
1310  else if (NMacroUtil::StringsAreEquivalent(field_name, "protein name") ||
1311  NMacroUtil::StringsAreEquivalent(field_name, "data.prot.name") ||
1312  NMacroUtil::StringsAreEquivalent(field_name, "data.prot.ec")) {
1313  return CreateNewProtein(src_feat, scope);
1314  }
1315  return CRef<CSeq_feat>(nullptr);
1316  }
1317 
1318  CRef<CSeq_feat> CreateNewGene(const CSeq_feat& src_feat, CScope& scope)
1319  {
1320  if (!src_feat.IsSetData() || !src_feat.IsSetLocation())
1321  return CRef<CSeq_feat>(nullptr);
1322 
1323  CRef<CSeq_feat> new_gene(new CSeq_feat);
1324  CConstRef<CSeq_loc> loc(&src_feat.GetLocation());
1325 
1326  CConstRef<CSeq_feat> cds_feat;
1327  if (src_feat.GetData().IsProt()) {
1328  CBioseq_Handle product = scope.GetBioseqHandle(src_feat.GetLocation());
1329  if (product) {
1330  cds_feat = sequence::GetCDSForProduct(product);
1331  }
1332  }
1333  else if (src_feat.GetData().IsCdregion()) {
1334  cds_feat = ConstRef(&src_feat);
1335  }
1336 
1337  if (cds_feat) {
1339  if (mrna) {
1340  loc = Ref(&mrna.GetLocation());
1341  }
1342  else {
1343  loc = Ref(&cds_feat->GetLocation());
1344  }
1345  }
1346 
1348  new_gene->SetLocation(*gene_loc);
1349  new_gene->SetPartial(new_gene->GetLocation().IsPartialStart(eExtreme_Biological) || new_gene->GetLocation().IsPartialStop(eExtreme_Biological));
1350  return new_gene;
1351  }
1352 
1353  CRef<CSeq_feat> CreateNewProtein(const CSeq_feat& src_feat, CScope& scope)
1354  {
1355  if (!src_feat.IsSetData() || !src_feat.IsSetLocation())
1356  return CRef<CSeq_feat>(nullptr);
1357 
1359  if (src_feat.GetData().IsCdregion()) {
1360  if (src_feat.IsSetProduct()) {
1361  CBioseq_Handle product = scope.GetBioseqHandle(src_feat.GetProduct());
1362  if (product && !CFeat_CI(product, CSeqFeatData::eSubtype_prot)) {
1363  SetProteinFeature(*prot, product, src_feat);
1364  }
1365  }
1366  }
1367  else if (src_feat.GetData().GetSubtype() == CSeqFeatData::eSubtype_mRNA) {
1369  if (cds && cds.IsSetProduct()) {
1370  CBioseq_Handle product = scope.GetBioseqHandle(cds.GetProduct());
1371  if (product && !CFeat_CI(product, CSeqFeatData::eSubtype_prot)) {
1372  SetProteinFeature(*prot, product, *cds.GetOriginalSeq_feat());
1373  }
1374  }
1375  }
1376  else if (src_feat.GetData().IsGene()) {
1377  list<CMappedFeat> cds_feats;
1378  feature::GetCdssForGene(scope.GetSeq_featHandle(src_feat), cds_feats);
1379  for (auto& it : cds_feats) {
1380  if (it.IsSetProduct()) {
1381  CBioseq_Handle product = scope.GetBioseqHandle(it.GetProduct());
1382  if (product && !CFeat_CI(product, CSeqFeatData::eSubtype_prot)) {
1383  SetProteinFeature(*prot, product, src_feat);
1384  continue;
1385  }
1386  }
1387  }
1388  }
1389  else if (src_feat.GetData().GetSubtype() == CSeqFeatData::eSubtype_mat_peptide_aa) {
1390  CBioseq_Handle product = scope.GetBioseqHandle(src_feat.GetLocation());
1391  if (product && !CFeat_CI(product, CSeqFeatData::eSubtype_prot)) {
1393  if (cds_feat) {
1394  SetProteinFeature(*prot, product, *cds_feat);
1395  }
1396  }
1397  }
1398  return prot;
1399  }
1400 
1401 }
1402 
1403 ///////////////////////////////////////////////////////////////////////////////
1404 /// class CMacroFunction_CopyStringQual
1405 /// Expected syntax:
1406 /// CopyStringQual( src_field, dest_field, existingtext_opt, delimiter)
1407 /// the last parameter is optional
1408 /// src_field_name and dest_field_name are subfields of the same object
1409 /// Can not use this function to copy from taxname to protein description
1410 
1412 
1414 {
1415  CObjectInfo oi = m_DataIter->GetEditedObject();
1416  CMQueryNodeValue::TObs src_objs;
1417  size_t index = 0;
1418  if (!x_GetSourceFields(oi, index, src_objs))
1419  return;
1420 
1421  CMQueryNodeValue::TObs dest_objs;
1422  if (!x_GetDestFields(oi, ++index, dest_objs))
1423  return;
1424 
1425  const string& action_type = m_Args[++index]->GetString();
1426  string delimiter = (++index < m_Args.size()) ? m_Args[index]->GetString() : kEmptyStr;
1427  m_ExistingText = NMacroUtil::ActionTypeToExistingTextOption(action_type, delimiter);
1428 
1429  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
1430  const CSeq_feat* src_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
1431  if (src_feat && m_Args[1]->IsString() && NStr::EndsWith(m_Args[1]->GetString(), "::product")) {
1433  for (auto&& it : src_objs) {
1434  CMQueryNodeValue::TObs src_prim_objs;
1435  NMacroUtil::GetPrimitiveObjectInfos(src_prim_objs, it);
1436 
1437  CObjectInfo src = src_prim_objs.front().field;
1438  string src_val = x_GetSourceString(src);
1439 
1440  string remainder;
1441  edit_feat->SetData().SetRna().SetRnaProductName(src_val, remainder);
1442  m_QualsChangedCount++;
1443  }
1444  }
1445  else {
1446  ChangeFields(src_objs, dest_objs);
1447  }
1448 
1449  if (m_QualsChangedCount) {
1450  if (!dest_objs.empty()) {
1451  NMacroUtil::CleanupForTaxnameChange(dest_objs.front(), oi);
1452  }
1453  m_DataIter->SetModified();
1455  log << m_DataIter->GetBestDescr() << ": copied " << m_QualsChangedCount << " qualifiers";
1456  x_LogFunction(log);
1457  }
1458 }
1459 
1461 {
1462  size_t arg_size = m_Args.size();
1463  if (arg_size != 3 && arg_size != 4) {
1464  return false;
1465  }
1466 
1467  for (size_t i = 0; i < 2; ++i) {
1468  CMQueryNodeValue::EType type = m_Args[i]->GetDataType();
1469  bool type_ok = (type == CMQueryNodeValue::eString)
1471  || (type == CMQueryNodeValue::eRef);
1472  if (!type_ok)
1473  return false;
1474  }
1475 
1476  for (size_t i = 2; i < arg_size; ++i) {
1477  if (m_Args[i]->GetDataType() != CMQueryNodeValue::eString)
1478  return false;
1479  }
1480  return true;
1481 }
1482 
1484 {
1485  if (dest.GetTypeFamily() != eTypeFamilyPrimitive) {
1486  return false;
1487  }
1488 
1489  string src_val = x_GetSourceString(src);
1490  string dest_val = dest.GetPrimitiveValueString();
1491  if (edit::AddValueToString(dest_val, src_val, m_ExistingText)) {
1492  return SetQualStringValue(dest, dest_val);
1493  }
1494  return false;
1495 }
1496 
1497 
1498 // class CMacroFunction_CopyFeatQual
1499 /// CopyFeatureQual(src_field, dest_feature_type, dest_feature_field, update_mrna, existing_text_opt, delimiter)
1500 /// The last parameter is optional
1501 /// The related mRNA is only updated if the action is successful and the destination feature is protein
1502 ///
1505 {
1506  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
1507  const CSeq_feat* src_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
1508  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
1509  if (!src_feat || !scope)
1510  return;
1511 
1512  const string& dest_field = m_Args[2]->GetString();
1513  if (dest_field.empty())
1514  return;
1515 
1516  CObjectInfo oi = m_DataIter->GetEditedObject();
1517  CMQueryNodeValue::TObs src_objs;
1518  if (!x_GetSourceFields(oi, 0, src_objs))
1519  return;
1520 
1521  // the destination field can be set at this point
1522  CSeqFeatData::ESubtype target_feature = NMacroUtil::GetFeatSubtype(m_Args[1]->GetString());
1523  NMacroUtil::TVecFeatList feat_list = edit::GetRelatedFeatures(*src_feat, target_feature, scope);
1524  CMQueryNodeValue::TObs dest_objs;
1525  bool changed = false, created = false;
1526  CRef<CSeq_feat> dest_feat;
1527  CSeq_feat_Handle fh;
1528  if (!feat_list.empty() && feat_list.size() == 1) {
1529  dest_feat.Reset(new CSeq_feat);
1530  dest_feat->Assign(*feat_list.front());
1531  if (!SetFeatDestinationField(dest_feat, dest_field, dest_objs)) {
1532  return;
1533  }
1534  fh = scope->GetSeq_featHandle(*feat_list.front());
1535  changed = true;
1536  }
1537  else {
1538  // new feature
1539  dest_feat = CreateNewRelatedFeature(*src_feat, dest_field, *scope);
1540  if (!dest_feat) return;
1541  if (!SetFeatDestinationField(dest_feat, dest_field, dest_objs)) {
1542  return;
1543  }
1544  created = true;
1545  if (src_feat->GetData().IsCdregion() && src_feat->IsSetXref() && dest_feat->GetData().IsProt()) {
1547  NON_CONST_ITERATE(CSeq_feat::TXref, it, edit_feat->SetXref()) {
1548  if ((*it)->IsSetData() && (*it)->GetData().IsProt()) {
1549  dest_feat->SetData().SetProt().Assign((*it)->GetData().GetProt());
1550  edit_feat->SetXref().erase(it);
1551  break;
1552  }
1553  }
1554  if (edit_feat->GetXref().empty()) {
1555  edit_feat->ResetXref();
1556  }
1557  }
1558  }
1559 
1560  size_t index = 3;
1561  bool update_mrna = m_Args[index]->GetBool();
1562  const string& action_type = m_Args[++index]->GetString();
1563  string delimiter = (++index < m_Args.size()) ? m_Args[index]->GetString() : kEmptyStr;
1564 
1566 
1567  if (IstRNAProductField(*dest_feat, dest_field)) {
1568  for (auto&& it : src_objs) {
1569  CMQueryNodeValue::TObs src_prim_objs;
1570  NMacroUtil::GetPrimitiveObjectInfos(src_prim_objs, it);
1571 
1572  CObjectInfo src = src_prim_objs.front().field;
1573  string src_val = x_GetSourceString(src);
1574 
1575  string remainder;
1576  dest_feat->SetData().SetRna().SetRnaProductName(src_val, remainder);
1578  }
1579  }
1580  else {
1581  ChangeFields(src_objs, dest_objs);
1582  }
1583 
1584  if (m_QualsChangedCount) {
1585  m_DataIter->SetModified();
1587  log << m_DataIter->GetBestDescr() << ": copied " << m_QualsChangedCount << " qualifiers";
1588 
1590  if (changed && fh) {
1591  cmd.Reset(new CCmdComposite("Change Related feature"));
1592  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *dest_feat)));
1593  }
1594  else if (created) {
1595  cmd.Reset(new CCmdComposite("Create feature"));
1596  CBioseq_Handle bsh = scope->GetBioseqHandle(dest_feat->GetLocation());
1597  cmd->AddCommand(*CRef<CCmdCreateFeatBioseq>(new CCmdCreateFeatBioseq(bsh, *dest_feat)));
1598  }
1599 
1600  if (update_mrna) {
1601  if (dest_feat->GetData().GetSubtype() == CSeqFeatData::eSubtype_prot) {
1602  string message;
1603  CRef<CCmdComposite> upd_cmd = UpdatemRNAProduct(*dest_feat, *scope, message);
1604  if (upd_cmd) {
1605  cmd->AddCommand(*upd_cmd);
1606  log << ", " << message;
1607  }
1608  }
1609  else if (src_feat->GetData().GetSubtype() == CSeqFeatData::eSubtype_prot) {
1611  string prot_product = edit_feat->GetData().GetProt().GetName().front();
1612  CRef<CCmdComposite> upd_cmd = UpdatemRNAProduct(prot_product, obj, *scope);
1613  if (upd_cmd) {
1614  cmd->AddCommand(*upd_cmd);
1615  log << ", applied " + prot_product + " to mRNA product name ";
1616  }
1617  }
1618  }
1619  m_DataIter->RunCommand(cmd, m_CmdComposite);
1620  x_LogFunction(log);
1621  }
1622 }
1623 
1625 {
1626  if (m_Args.size() < 5 || m_Args.size() > 6)
1627  return false;
1628 
1629  if (!( m_Args[0]->IsString() || m_Args[0]->AreObjects() || m_Args[0]->IsRef()))
1630  return false;
1631 
1632  auto type = m_Args[0]->GetDataType();
1633  for (size_t index = 1; index < m_Args.size(); ++index) {
1635  if (m_Args[index]->GetDataType() != type)
1636  return false;
1637  }
1638  return true;
1639 }
1640 
1641 
1642 ///////////////////////////////////////////////////////////////////////////////
1643 // CMacroFunction_CopyRNARelQual
1644 /// CopyRnaRelQual('rna'/'gene', src_field, 'gene'/'rna', dest_field, existing_text_opt, delimiter)
1645 /// The last parameter is optional
1646 /// Use this function when you need to copy from/to an RNA qualifier and a Gene qualifier
1647 /// Don't use this function to copy between two RNA qualifiers
1650 {
1651  // The iterator should be an RNA feature
1652  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
1653  const CSeq_feat* rna_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
1654 
1655  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
1656  if (!rna_feat || !scope)
1657  return;
1658 
1659  if (rna_feat->IsSetData() && !rna_feat->GetData().IsRna())
1660  return;
1661 
1662  const string& src_feat = m_Args[0]->GetString();
1663  const string& dest_feat = m_Args[2]->GetString();
1664  if (src_feat == "rna" && src_feat == dest_feat)
1665  return;
1666 
1667  if ((src_feat != "rna" && src_feat != "gene") || (dest_feat != "rna" && dest_feat != "gene"))
1668  return;
1669 
1670  size_t index = 4;
1671  const string& action_type = m_Args[index]->GetString();
1672  string delimiter = (++index < m_Args.size()) ? m_Args[index]->GetString() : kEmptyStr;
1674 
1675  if (src_feat == "rna" && dest_feat == "gene") {
1676  CObjectInfo oi = m_DataIter->GetEditedObject();
1677  CMQueryNodeValue::TObs src_objs;
1678  if (!x_GetSourceFields(oi, 1, src_objs))
1679  return;
1680 
1681  const string dest_field = m_Args[3]->GetString();
1682  // the destination field can be set at this point
1684  CMQueryNodeValue::TObs dest_objs;
1685  bool changed = false, created = false;
1686  CRef<CSeq_feat> dest_feat;
1687  CSeq_feat_Handle fh;
1688  if (!feat_list.empty() && feat_list.size() == 1) {
1689  dest_feat.Reset(new CSeq_feat);
1690  dest_feat->Assign(*feat_list.front());
1691  if (!SetFeatDestinationField(dest_feat, dest_field, dest_objs)) {
1692  return;
1693  }
1694  fh = scope->GetSeq_featHandle(*feat_list.front());
1695  changed = true;
1696  }
1697  else {
1698  // new feature
1699  dest_feat = CreateNewRelatedFeature(*rna_feat, dest_field, *scope);
1700  if (!dest_feat) return;
1701  if (!SetFeatDestinationField(dest_feat, dest_field, dest_objs)) {
1702  return;
1703  }
1704  created = true;
1705  }
1706 
1707  ChangeFields(src_objs, dest_objs);
1708 
1709  if (m_QualsChangedCount) {
1711  if (changed && fh) {
1712  cmd.Reset(new CCmdComposite("Change Related feature"));
1713  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *dest_feat)));
1714  }
1715  else if (created) {
1716  cmd.Reset(new CCmdComposite("Create feature"));
1717  CBioseq_Handle bsh = scope->GetBioseqHandle(dest_feat->GetLocation());
1718  cmd->AddCommand(*CRef<CCmdCreateFeatBioseq>(new CCmdCreateFeatBioseq(bsh, *dest_feat)));
1719  }
1720 
1721  m_DataIter->RunCommand(cmd, m_CmdComposite);
1723  log << m_DataIter->GetBestDescr() << ": copied " << m_QualsChangedCount << " qualifiers";
1724  x_LogFunction(log);
1725  }
1726  }
1727  else if (src_feat == "gene" && dest_feat == "gene") {
1729  CMQueryNodeValue::TObs src_objs, dest_objs;
1730 
1731  CRef<CSeq_feat> gene_feat;
1732  CSeq_feat_Handle fh;
1733  if (!feat_list.empty() && feat_list.size() == 1) {
1734  gene_feat.Reset(new CSeq_feat);
1735  gene_feat->Assign(*feat_list.front());
1736 
1737  CObjectInfo gene_oi(gene_feat.GetPointer(), gene_feat->GetThisTypeInfo());
1738  if (!x_GetSourceFields(gene_oi, 1, src_objs))
1739  return;
1740 
1741  if (!x_GetDestFields(gene_oi, 3, dest_objs))
1742  return;
1743 
1744  fh = scope->GetSeq_featHandle(*feat_list.front());
1745  }
1746  else {
1747  // no gene was found
1748  return;
1749  }
1750 
1751  ChangeFields(src_objs, dest_objs);
1752 
1753  if (m_QualsChangedCount) {
1755  if (fh) {
1756  cmd.Reset(new CCmdComposite("Change Related feature"));
1757  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *gene_feat)));
1758  }
1759 
1760  m_DataIter->RunCommand(cmd, m_CmdComposite);
1762  log << m_DataIter->GetBestDescr() << ": copied " << m_QualsChangedCount << " qualifiers";
1763  x_LogFunction(log);
1764  }
1765  }
1766  else if (src_feat == "gene" && dest_feat == "rna") {
1767 
1769  CMQueryNodeValue::TObs src_objs, dest_objs;
1770  CRef<CSeq_feat> gene_feat;
1771  if (!feat_list.empty() && feat_list.size() == 1) {
1772  gene_feat.Reset(new CSeq_feat);
1773  gene_feat->Assign(*feat_list.front());
1774 
1775  CObjectInfo gene_oi(gene_feat.GetPointer(), gene_feat->GetThisTypeInfo());
1776  if (!x_GetSourceFields(gene_oi, 1, src_objs))
1777  return;
1778  }
1779  else {
1780  // no gene was found
1781  return;
1782  }
1783 
1784  CObjectInfo oi = m_DataIter->GetEditedObject();
1785  if (!x_GetDestFields(oi, 3, dest_objs))
1786  return;
1787 
1789  if (m_Args[3]->IsString() && NStr::EndsWith(m_Args[3]->GetString(), "::product")) {
1790  for (auto&& it : src_objs) {
1791  CMQueryNodeValue::TObs src_prim_objs;
1792  NMacroUtil::GetPrimitiveObjectInfos(src_prim_objs, it);
1793 
1794  CObjectInfo src = src_prim_objs.front().field;
1795  string src_val = x_GetSourceString(src);
1796 
1797  string remainder;
1798  edit_feat->SetData().SetRna().SetRnaProductName(src_val, remainder);
1800  }
1801  }
1802  else {
1803  ChangeFields(src_objs, dest_objs);
1804  }
1805 
1806  if (m_QualsChangedCount) {
1807  m_DataIter->SetModified();
1809  log << m_DataIter->GetBestDescr() << ": copied " << m_QualsChangedCount << " qualifiers";
1810  x_LogFunction(log);
1811  }
1812  }
1813 }
1814 
1816 {
1817  if (m_Args.size() < 5 || m_Args.size() > 6)
1818  return false;
1819 
1820  if (!m_Args[0]->IsString() || !m_Args[2]->IsString() || !m_Args[4]->IsString())
1821  return false;
1822 
1823  for (size_t index = 1; index < 4; index += 2) {
1824  if (!(m_Args[index]->IsString() || m_Args[index]->AreObjects() || m_Args[index]->IsRef()))
1825  return false;
1826  }
1827  return (m_Args.size() == 5 || (m_Args.size() == 6 && m_Args[5]->IsString()));
1828 }
1829 
1830 
1831 ///////////////////////////////////////////////////////////////////////////////
1832 // CMacroFunction_SetRelFeatQual
1833 /// SetRelatedFeatureQual(feat_type, field_name, new_value, existing_text_option, delimiter, remove_blank, update_mrna)
1834 /// The last three parameters are optional
1835 ///
1838 {
1839  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
1840  const CSeq_feat* src_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
1841  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
1842  if (!src_feat || !scope)
1843  return;
1844 
1845  CObjectInfo oi = m_DataIter->GetEditedObject();
1846  const string& field_name = m_Args[1]->GetString();
1847  CSeqFeatData::ESubtype feat_type = NMacroUtil::GetFeatSubtype(m_Args[0]->GetString());
1848  NMacroUtil::TVecFeatList feat_list = edit::GetRelatedFeatures(*src_feat, feat_type, scope);
1849 
1850  size_t index = 2;
1851  string newValue = NMacroUtil::GetStringValue(m_Args[index]);
1852  const string& action_type = m_Args[++index]->GetString();
1853  string delimiter;
1854  bool remove_field = false;
1855  bool update_mrna = false;
1856  size_t arg_nr = m_Args.size();
1857 
1858  if (++index < arg_nr) {
1859  if (m_Args[index]->IsString()) {
1860  delimiter = m_Args[index]->GetString();
1861  if (++index < arg_nr) {
1862  remove_field = m_Args[index]->GetBool();
1863  if (++index < arg_nr)
1864  update_mrna = m_Args[index]->GetBool();
1865  }
1866  }
1867  else if (m_Args[index]->IsBool()) {
1868  remove_field = m_Args[index]->GetBool();
1869  if (++index < arg_nr)
1870  update_mrna = m_Args[index]->GetBool();
1871  }
1872  }
1874 
1875  if (!newValue.empty()) {
1877  bool changed = false, created = false;
1878  CRef<CSeq_feat> dest_feat;
1879  CSeq_feat_Handle fh;
1880  if (!feat_list.empty() && feat_list.size() == 1) {
1881  dest_feat.Reset(new CSeq_feat);
1882  dest_feat->Assign(*feat_list.front());
1883  if (!SetFeatDestinationField(dest_feat, field_name, objs)) {
1884  return;
1885  }
1886  fh = scope->GetSeq_featHandle(*feat_list.front());
1887  changed = true;
1888  }
1889  else {
1890  // new feature
1891  dest_feat = CreateNewRelatedFeature(*src_feat, field_name, *scope);
1892  if (!dest_feat) return;
1893  if (!SetFeatDestinationField(dest_feat, field_name, objs)) {
1894  return;
1895  }
1896  created = true;
1897  if (src_feat->GetData().IsCdregion() && src_feat->IsSetXref() && dest_feat->GetData().IsProt()) {
1899  NON_CONST_ITERATE(CSeq_feat::TXref, it, edit_feat->SetXref()) {
1900  if ((*it)->IsSetData() && (*it)->GetData().IsProt()) {
1901  dest_feat->SetData().SetProt().Assign((*it)->GetData().GetProt());
1902  edit_feat->SetXref().erase(it);
1904  break;
1905  }
1906  }
1907  if (edit_feat->GetXref().empty()) {
1908  edit_feat->ResetXref();
1909  }
1910  }
1911  }
1912 
1913  vector<string> new_values;
1914  x_SetFields(objs, newValue, existing_text, new_values);
1915 
1916  if (m_QualsChangedCount) {
1917  m_DataIter->SetModified();
1919  log << m_DataIter->GetBestDescr();
1920  for (size_t i = 0; i < new_values.size(); ++i) {
1921  log << ": set '" << new_values[i] << "' as a new value";
1922  }
1923 
1924  if (changed && fh) {
1925  CRef<CCmdComposite> cmd(new CCmdComposite("Change Related feature"));
1926  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *dest_feat)));
1927  if (update_mrna && dest_feat->GetData().GetSubtype() == CSeqFeatData::eSubtype_prot) {
1928  string prot_product = dest_feat->GetData().GetProt().GetName().front();
1929  CRef<CCmdComposite> upd_cmd = UpdatemRNAProduct(prot_product, feat_list.front(), *scope);
1930  if (upd_cmd) {
1931  cmd->AddCommand(*upd_cmd);
1932  log << ", applied " + prot_product + " to mRNA product name ";
1933  }
1934  }
1935  m_DataIter->RunCommand(cmd, m_CmdComposite);
1936  }
1937  else if (created) {
1938  CRef<CCmdComposite> cmd(new CCmdComposite("Create feature"));
1939  CBioseq_Handle bsh = scope->GetBioseqHandle(dest_feat->GetLocation());
1940  cmd->AddCommand(*CRef<CCmdCreateFeatBioseq>(new CCmdCreateFeatBioseq(bsh, *dest_feat)));
1941  if (update_mrna && dest_feat->GetData().GetSubtype() == CSeqFeatData::eSubtype_prot) {
1942  string message;
1943  CRef<CCmdComposite> upd_cmd = UpdatemRNAProduct(*dest_feat, *scope, message);
1944  if (upd_cmd) {
1945  cmd->AddCommand(*upd_cmd);
1946  log << ", " << message;
1947  }
1948  }
1949  m_DataIter->RunCommand(cmd, m_CmdComposite);
1950  }
1951 
1952  x_LogFunction(log);
1953  }
1954  }
1955  else if (remove_field) {
1957  CRef<CSeq_feat> dest_feat;
1958  CSeq_feat_Handle fh;
1959  if (!feat_list.empty() && feat_list.size() == 1) {
1960  dest_feat.Reset(new CSeq_feat);
1961  dest_feat->Assign(*feat_list.front());
1962  if (!GetFeatDestinationField(dest_feat, field_name, objs)) {
1963  return;
1964  }
1965  fh = scope->GetSeq_featHandle(*feat_list.front());
1966  }
1967 
1968  for (auto& it : objs) {
1969  if (RemoveFieldByName(it)) {
1971  }
1972  }
1973 
1974  if (m_QualsChangedCount) {
1976  if (fh) {
1977  CCleanup cleanup(scope);
1978  cleanup.BasicCleanup(*dest_feat);
1979 
1980  CRef<CCmdComposite> cmd(new CCmdComposite("Change Related feature"));
1981  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *dest_feat)));
1982  log << m_DataIter->GetBestDescr() << ": removed " << m_QualsChangedCount << " qualifiers";
1983 
1984  if (update_mrna && dest_feat->GetData().GetSubtype() == CSeqFeatData::eSubtype_prot) {
1985  string message;
1986  CRef<CCmdComposite> upd_cmd = UpdatemRNAProduct(*dest_feat, *scope, message);
1987  if (upd_cmd) {
1988  cmd->AddCommand(*upd_cmd);
1989  log << ", " << message;
1990  }
1991  }
1992  m_DataIter->RunCommand(cmd, m_CmdComposite);
1993  }
1994  x_LogFunction(log);
1995  }
1996  }
1997 }
1998 
2000 {
2001  // can accept as its first parameter: objects, string or reference
2002  size_t arg_nr = m_Args.size();
2003  if (arg_nr < 4 && arg_nr > 7) {
2004  return false;
2005  }
2006 
2007  NMacroUtil::GetPrimitiveFromRef(m_Args[2].GetNCObject());
2008  size_t index = 0;
2009  for (; index < 4; ++index) {
2010  if (!m_Args[index]->IsString())
2011  return false;
2012  }
2013 
2014  if (index < arg_nr && (!m_Args[index]->IsString() && !m_Args[index]->IsBool())) return false;
2015  if (++index < arg_nr && !m_Args[index]->IsBool()) return false;
2016  if (++index < arg_nr && !m_Args[index]->IsBool()) return false;
2017  return true;
2018 }
2019 
2020 
2021 ///////////////////////////////////////////////////////////////////////////////
2022 // CMacroFunction_EditRelFeatQual
2023 /// EditRelatedFeatureQual(feat_type, field_name, find_text, repl_text, location, case_sensitive, is_regex)
2024 ///
2025 const char* CMacroFunction_EditRelFeatQual::sm_FunctionName = "EditRelatedFeatureQual";
2027 {
2028  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
2029  const CSeq_feat* src_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
2030  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
2031  if (!src_feat || !scope)
2032  return;
2033 
2034  size_t index = 2;
2035  const string& find_txt = NMacroUtil::GetStringValue(m_Args[index]);
2036  string repl_txt = NMacroUtil::GetStringValue(m_Args[++index]);
2037  const string& location = m_Args[++index]->GetString();
2038  bool case_sensitive = m_Args[++index]->GetBool();
2039  bool is_regex = (++index < m_Args.size()) ? m_Args[index]->GetBool() : false;
2040 
2041  CObjectInfo oi = m_DataIter->GetEditedObject();
2042  const string& field_name = m_Args[1]->GetString();
2043  CSeqFeatData::ESubtype feat_type = NMacroUtil::GetFeatSubtype(m_Args[0]->GetString());
2044  NMacroUtil::TVecFeatList feat_list = edit::GetRelatedFeatures(*src_feat, feat_type, scope);
2045 
2047  CRef<CSeq_feat> dest_feat;
2048  CSeq_feat_Handle fh;
2049  if (!feat_list.empty() && feat_list.size() == 1) {
2050  dest_feat.Reset(new CSeq_feat);
2051  dest_feat->Assign(*feat_list.front());
2052  if (!GetFeatDestinationField(dest_feat, field_name, objs)) {
2053  return;
2054  }
2055  fh = scope->GetSeq_featHandle(*feat_list.front());
2056  }
2057 
2058  x_EditFields(objs, find_txt, repl_txt, s_GetLocFromName(location), case_sensitive, is_regex);
2059  if (m_QualsChangedCount) {
2060  if (fh) {
2061  CRef<CCmdComposite> cmd(new CCmdComposite("Change Related feature"));
2062  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *dest_feat)));
2063  m_DataIter->RunCommand(cmd, m_CmdComposite);
2064  }
2065 
2067  log << m_DataIter->GetBestDescr() << ": edited " << m_QualsChangedCount << " qualifiers, replaced " << find_txt;
2068  if (NStr::IsBlank(repl_txt)) {
2069  repl_txt.assign("''");
2070  }
2071  log << " with " << repl_txt;
2072  x_LogFunction(log);
2073  }
2074 }
2075 
2077 {
2078  if (m_Args.size() != 6 && m_Args.size() != 7)
2079  return false;
2080 
2081  for (size_t index = 2; index < 4; index++) {
2082  if (m_Args[index]->GetDataType() != CMQueryNodeValue::eString && m_Args[index]->GetDataType() != CMQueryNodeValue::eInt) {
2083  return false;
2084  }
2085  }
2086 
2087  if (m_Args.size() == 7) {
2088  if (m_Args.back()->GetDataType() != CMQueryNodeValue::eBool)
2089  return false;
2090  }
2091  return (m_Args[0]->GetDataType() == CMQueryNodeValue::eString
2092  && m_Args[1]->GetDataType() == CMQueryNodeValue::eString
2093  && m_Args[5]->GetDataType() == CMQueryNodeValue::eBool);
2094 }
2095 
2096 
2097 ///////////////////////////////////////////////////////////////////////////////
2098 // CMacroFunction_RmvRelFeatQual
2099 /// RemoveRelatedFeatureQual(feat_type, field_name)
2100 ///
2101 DEFINE_MACRO_FUNCNAME(CMacroFunction_RmvRelFeatQual, "RemoveRelatedFeatureQual")
2102 void CMacroFunction_RmvRelFeatQual::TheFunction()
2103 {
2104  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
2105  const CSeq_feat* src_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
2106  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
2107  if (!src_feat || !scope)
2108  return;
2109 
2110  CObjectInfo oi = m_DataIter->GetEditedObject();
2111  const string& field_name = m_Args[1]->GetString();
2112  CSeqFeatData::ESubtype feat_type = NMacroUtil::GetFeatSubtype(m_Args[0]->GetString());
2113  NMacroUtil::TVecFeatList feat_list = edit::GetRelatedFeatures(*src_feat, feat_type, scope);
2114 
2116  CRef<CSeq_feat> dest_feat;
2117  CSeq_feat_Handle fh;
2118  if (!feat_list.empty() && feat_list.size() == 1) {
2119  dest_feat.Reset(new CSeq_feat);
2120  dest_feat->Assign(*feat_list.front());
2121  if (!GetFeatDestinationField(dest_feat, field_name, objs)) {
2122  return;
2123  }
2124  fh = scope->GetSeq_featHandle(*feat_list.front());
2125  }
2126 
2127  for (auto& it : objs) {
2128  if (RemoveFieldByName(it)) {
2129  m_QualsChangedCount++;
2130  }
2131  }
2132 
2133 
2134  if (m_QualsChangedCount) {
2135  if (fh) {
2136  CCleanup cleanup(scope);
2137  cleanup.BasicCleanup(*dest_feat);
2138 
2139  CRef<CCmdComposite> cmd(new CCmdComposite("Change Related feature"));
2140  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *dest_feat)));
2141  m_DataIter->RunCommand(cmd, m_CmdComposite);
2142  }
2144  log << m_DataIter->GetBestDescr() << ": removed " << m_QualsChangedCount << " qualifiers";
2145  x_LogFunction(log);
2146  }
2147 }
2148 
2149 bool CMacroFunction_RmvRelFeatQual::x_ValidArguments() const
2150 {
2151  if (m_Args.size() != 2)
2152  return false;
2153 
2154  //TODO - extend it to accept reference, for example: gene synonym with a constraint
2155  return (m_Args[0]->IsString() && m_Args[1]->IsString());
2156 }
2157 
2158 
2159 ///////////////////////////////////////////////////////////////////////////////
2160 // class CMacroFunction_RmvOutsideRelFeatQual
2161 /// RmvOutsideRelatedFeatureQual(feat_type, field_name, before_match(b), left_del(str), rmv_left(b),
2162 /// after_match(b), right_del(str), rmv_right(b), case_insensitive(b), whole_word(b), update_mrna(b))
2163 
2164 DEFINE_MACRO_FUNCNAME(CMacroFunction_RmvOutsideRelFeatQual, "RmvOutsideRelatedFeatureQual")
2165 
2167 {
2168  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
2169  const CSeq_feat* src_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
2170  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
2171  if (!src_feat || !scope)
2172  return;
2173 
2174  CObjectInfo oi = m_DataIter->GetEditedObject();
2175  const string& field_name = m_Args[1]->GetString();
2176  CSeqFeatData::ESubtype feat_type = NMacroUtil::GetFeatSubtype(m_Args[0]->GetString());
2177  NMacroUtil::TVecFeatList feat_list = edit::GetRelatedFeatures(*src_feat, feat_type, scope);
2178 
2179 
2181  CRef<CSeq_feat> dest_feat;
2182  CSeq_feat_Handle fh;
2183  if (!feat_list.empty() && feat_list.size() == 1) {
2184  dest_feat.Reset(new CSeq_feat);
2185  dest_feat->Assign(*feat_list.front());
2186  if (!GetFeatDestinationField(dest_feat, field_name, objs)) {
2187  return;
2188  }
2189  fh = scope->GetSeq_featHandle(*feat_list.front());
2190  }
2191 
2192  CRef<CRemoveTextOptions> options = x_GetRemoveTextOptions(2);
2193  x_RmvOutsideFields(objs, *options);
2194  if (m_QualsChangedCount) {
2195  if (fh) {
2196  CRef<CCmdComposite> cmd(new CCmdComposite("Change Related feature"));
2197  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *dest_feat)));
2198  m_DataIter->RunCommand(cmd, m_CmdComposite);
2199  }
2200 
2202  log << m_DataIter->GetBestDescr() << ": removed text outside string in " << m_QualsChangedCount << " qualifiers";
2203 
2204  bool update_mrna = (m_Args.size() == 11) ? m_Args[10]->GetBool() : false;
2205  if (update_mrna && dest_feat->GetData().GetSubtype() == CSeqFeatData::eSubtype_prot) {
2206  string message;
2207  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
2208  string prot_product = dest_feat->GetData().GetProt().GetName().front();
2209  CRef<CCmdComposite> cmd = UpdatemRNAProduct(prot_product, feat_list.front(), *scope);
2210  if (cmd) {
2211  m_DataIter->RunCommand(cmd, m_CmdComposite);
2212  log << ", applied " + prot_product + " to mRNA product name ";
2213  }
2214  }
2215 
2216  x_LogFunction(log);
2217  }
2218 }
2219 
2221 {
2222  if (m_Args.size() != 10 && m_Args.size() != 11)
2223  return false;
2224 
2225  if (m_Args[0]->GetDataType() != CMQueryNodeValue::eString || m_Args[1]->GetDataType() != CMQueryNodeValue::eString)
2226  return false;
2227 
2228  return x_CheckArguments(2);
2229 }
2230 
2231 
2232 // IOperateOnTwoQuals interface
2234 {
2235  _ASSERT(!src_objs.empty() && !dest_objs.empty());
2236  CMQueryNodeValue::TObs::iterator src_it = src_objs.begin();
2237  CMQueryNodeValue::TObs::iterator dest_it = dest_objs.begin();
2238 
2239  while (src_it != src_objs.end()) {
2240  CMQueryNodeValue::TObs src_prim_objs;
2241  NMacroUtil::GetPrimitiveObjectInfos(src_prim_objs, *src_it);
2242  CMQueryNodeValue::TObs dest_prim_objs;
2243  NMacroUtil::GetPrimitiveObjectInfos(dest_prim_objs, *dest_it);
2244  if (dest_prim_objs.empty() && dest_it->field.GetTypeFamily() == eTypeFamilyContainer) {
2245  // add new element when the container is empty
2246  CObjectInfo new_oi(dest_it->field.AddNewElement());
2247  dest_prim_objs.push_back(CMQueryNodeValue::SResolvedField(dest_it->field, new_oi));
2248  }
2249  for (auto& it : src_prim_objs) {
2250  x_ChangeFields(it.field, dest_prim_objs.front().field);
2251  }
2252 
2253  ++src_it;
2254  ++dest_it;
2255  if (dest_it == dest_objs.end()) {
2256  --dest_it;
2257  }
2258  }
2259 }
2260 
2262 {
2263  if (index >= m_Args.size())
2264  return false;
2265 
2266  // the source field has to be set
2267  CMQueryNodeValue::EType src_type = m_Args[index]->GetDataType();
2268 
2269  if (src_type == CMQueryNodeValue::eString) {
2270  if (!GetFieldsByName(&result, oi, m_Args[index]->GetString()))
2271  return false;
2272  }
2273  else if (src_type == CMQueryNodeValue::eObjects) {
2274  result = m_Args[index]->GetObjects();
2275  }
2276  else if (src_type == CMQueryNodeValue::eRef) {
2277  x_GetObjectsFromRef(result, index);
2279  }
2280 
2281  return (!result.empty());
2282 }
2283 
2285 {
2286  // the destination field might be set during this action
2287  CMQueryNodeValue::EType dest_type = m_Args[index]->GetDataType();
2288 
2289  if (dest_type == CMQueryNodeValue::eString) {
2290  const string& dest_field = m_Args[index]->GetString();
2291  CConstRef<CObject> object = m_DataIter->GetScopedObject().object;
2292  bool valid = GetDestinationObjects(object, oi, dest_field, result);
2293  if (valid && result.empty()) // for tRNA product
2294  return valid;
2295  }
2296  else if (dest_type == CMQueryNodeValue::eObjects) {
2297  result = m_Args[index]->GetObjects();
2298  }
2299  else if (dest_type == CMQueryNodeValue::eRef) {
2300  x_GetObjectsFromRef(result, index);
2301  }
2302  return !result.empty();
2303 }
2304 
2306 {
2307  string src_val;
2308  if (src.GetTypeFamily() == eTypeFamilyPrimitive) {
2309  switch (src.GetPrimitiveValueType()) {
2310  case ePrimitiveValueString:
2311  src_val = src.GetPrimitiveValueString();
2312  // strip_name is not implemented yet
2313  break;
2314  case ePrimitiveValueEnum: //e.g., codon-start
2315  src_val = NStr::IntToString(src.GetPrimitiveValueInt());
2316  break;
2317  case ePrimitiveValueInteger: // e.g., local_id
2318  src_val = NStr::IntToString(src.GetPrimitiveValueInt4());
2319  break;
2320  case ePrimitiveValueReal:
2322  break;
2323  case ePrimitiveValueBool:
2324  src_val = NStr::BoolToString(src.GetPrimitiveValueBool());
2325  break;
2326  default:
2327  break;
2328  }
2329  }
2330  else if (src.GetTypeFamily() == eTypeFamilyClass) {
2331  if (src.GetName() == "Dbtag") {
2333  if (tag) {
2334  tag->GetLabel(&src_val);
2335  }
2336  }
2337  }
2338  return src_val;
2339 }
2340 
2341 
2342 ///////////////////////////////////////////////////////////////////////////////
2343 /// class CMacroFunction_ConvertStringQual
2344 /// ConvertStringQual(src_field, dst_field, capitalization, strip_name, existing_text_opt, delimiter)
2345 /// last parameter is optional
2346 /// The function will NOT delete the src_field.
2347 /// If the user wants to delete the src_field, (s)he should use RemoveQual() or RemoveModifier() functions
2348 ///
2350 
2352 {
2353  CObjectInfo oi = m_DataIter->GetEditedObject();
2354  CMQueryNodeValue::TObs src_objs;
2355  size_t index = 0;
2356  if (!x_GetSourceFields(oi, index, src_objs))
2357  return;
2358 
2359  CMQueryNodeValue::TObs dest_objs;
2360  if (!x_GetDestFields(oi, ++index, dest_objs))
2361  return;
2362 
2363  const string& capitalization = m_Args[++index]->GetString();
2364  //bool strip_name = m_Args[++index]->GetBool();
2365  //strip_name = false; // this option is not implemented ( it's false by default)
2366  ++index;
2367  const string& action_type = m_Args[++index]->GetString();
2368  string delimiter = (++index < m_Args.size()) ? m_Args[index]->GetString() : kEmptyStr;
2369  m_ExistingText = NMacroUtil::ActionTypeToExistingTextOption(action_type, delimiter);
2370  m_CapChange = NMacroUtil::ConvertStringtoCapitalOption(capitalization);
2371 
2372  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
2373  const CSeq_feat* src_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
2374  if (src_feat && m_Args[1]->IsString() && NStr::EndsWith(m_Args[1]->GetString(), "::product")) {
2376  for (auto&& it : src_objs) {
2377  CMQueryNodeValue::TObs src_prim_objs;
2378  NMacroUtil::GetPrimitiveObjectInfos(src_prim_objs, it);
2379 
2380  CObjectInfo src = src_prim_objs.front().field;
2381  string src_val = x_GetSourceString(src);
2382 
2383  string remainder;
2384  edit_feat->SetData().SetRna().SetRnaProductName(src_val, remainder);
2385  m_QualsChangedCount++;
2386  }
2387  }
2388  else {
2389  ChangeFields(src_objs, dest_objs);
2390  }
2391 
2392  if (m_QualsChangedCount) {
2393  if (!dest_objs.empty()) {
2394  NMacroUtil::CleanupForTaxnameChange(dest_objs.front(), oi);
2395  }
2396  m_DataIter->SetModified();
2398  log << m_DataIter->GetBestDescr() << ": converted " << m_QualsChangedCount << " qualifiers";
2399  x_LogFunction(log);
2400  }
2401 }
2402 
2404 {
2405  if (dest.GetTypeFamily() != eTypeFamilyPrimitive) {
2406  return false;
2407  }
2408 
2409  string src_val = x_GetSourceString(src);
2411  string dest_val = dest.GetPrimitiveValueString();
2412  if (edit::AddValueToString(dest_val, src_val, m_ExistingText)) {
2413  return SetQualStringValue(dest, dest_val);
2414  }
2415  }
2416  return false;
2417 }
2418 
2420 {
2421  string src_val = IOperateOnTwoQuals::x_GetSourceString(src);
2422  CSeq_entry_Handle seh = m_DataIter->GetSEH();
2423  FixCapitalizationInString(seh, src_val, m_CapChange);
2424  return src_val;
2425 }
2426 
2427 
2429 {
2430  size_t as = m_Args.size();
2431  if (!(as == 5 || as == 6)) {
2432  return false;
2433  }
2434 
2435  for (size_t i = 0; i < 2; ++i) {
2436  CMQueryNodeValue::EType type = m_Args[i]->GetDataType();
2437  bool type_ok = (type == CMQueryNodeValue::eString)
2439  || (type == CMQueryNodeValue::eRef);
2440  if (!type_ok)
2441  return false;
2442  }
2443 
2444  bool m_Args_ok = (m_Args[2]->GetDataType() == CMQueryNodeValue::eString);
2445  m_Args_ok = m_Args_ok && (m_Args[3]->GetDataType() == CMQueryNodeValue::eBool)
2446  && (m_Args[4]->GetDataType() == CMQueryNodeValue::eString);
2447 
2448  if (as == 6) {
2449  m_Args_ok = m_Args_ok && (m_Args[5]->GetDataType() == CMQueryNodeValue::eString);
2450  }
2451 
2452  if (!m_Args_ok) {
2453  return false;
2454  }
2455 
2456  return true;
2457 }
2458 
2459 
2460 ///////////////////////////////////////////////////////////////////////////////
2461 /// class CMacroFunction_SwapQual
2462 /// SwapQual(src_fieldname, dest_fieldname)
2463 /// Swaps the content of two fields. If one field is blank/does not exist, the other field will be removed
2464 ///
2466 
2467 void CMacroFunction_SwapQual::TheFunction()
2468 {
2469  CObjectInfo oi = m_DataIter->GetEditedObject();
2470  CMQueryNodeValue::TObs src_objs;
2471  CMQueryNodeValue::TObs dest_objs;
2472  size_t src_index = 0, dest_index = 1;
2473 
2474  if ((m_Args.size() == 3 && m_Args[0]->GetDataType() != CMQueryNodeValue::eString)
2475  || m_Args.size() == 4) {
2476  dest_index = 2;
2477  }
2478 
2479  // check that at least one of the fields exist
2480  bool src_set = x_DoFieldsExist(oi, src_objs, src_index);
2481  bool dest_set = x_DoFieldsExist(oi, dest_objs, dest_index);
2482 
2483  if (!src_set && !dest_set)
2484  return;
2485 
2486  // special attention to gene qualifiers that are removed from gene Xrefs
2487  bool is_gene_suppressed_before = false;
2488  bool is_gene_suppressed_after = false;
2489  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
2490  if (dynamic_cast<const CSeq_feat*>(obj.GetPointer())) {
2492  auto gene_xref = feat->GetGeneXref();
2493  is_gene_suppressed_before = gene_xref && gene_xref->IsSuppressed();
2494  }
2495 
2496  if (!src_set) {
2497  x_SetFields(oi, src_objs, src_index);
2498  }
2499  if (!dest_set) {
2500  x_SetFields(oi, dest_objs, dest_index);
2501  }
2502 
2503  if (src_set && dest_set) {
2504  CMQueryNodeValue::TObs::iterator src_it = src_objs.begin();
2505  CMQueryNodeValue::TObs::iterator dest_it = dest_objs.begin();
2506 
2507  while (src_it != src_objs.end() && dest_it != dest_objs.end()) {
2508  CMQueryNodeValue::TObs src_prim_objs;
2509  NMacroUtil::GetPrimitiveObjInfosWithContainers(src_prim_objs, *src_it);
2510  CMQueryNodeValue::TObs dest_prim_objs;
2511  NMacroUtil::GetPrimitiveObjInfosWithContainers(dest_prim_objs, *dest_it);
2512  if (dest_prim_objs.empty() && dest_it->field.GetTypeFamily() == eTypeFamilyContainer) {
2513  // add new element when the container is empty
2514  CObjectInfo new_oi(dest_it->field.AddNewElement());
2515  dest_prim_objs.push_back(CMQueryNodeValue::SResolvedField(dest_it->field, new_oi));
2516  }
2517  x_SwapFields(src_prim_objs.front().field, dest_prim_objs.front().field);
2518 
2519  ++src_it;
2520  ++dest_it;
2521  }
2522  NMacroUtil::CleanupForTaxnameChange(src_objs.front(), oi);
2523  NMacroUtil::CleanupForTaxnameChange(dest_objs.front(), oi);
2524  }
2525  else if (!src_set) {
2526  // copy destination field into the source field
2527  x_CopyFields(dest_objs, src_objs);
2528 
2529  bool is_taxname = NMacroUtil::IsTaxname(dest_objs.front());
2530  // delete destination field
2531  NON_CONST_ITERATE(CMQueryNodeValue::TObs, it, dest_objs) {
2532  RemoveFieldByName(*it);
2533  }
2534  if (is_taxname) {
2536  }
2537  }
2538  else if (!dest_set) {
2539  // copy source field into the destination field
2540  x_CopyFields(src_objs, dest_objs);
2541 
2542  bool is_taxname = NMacroUtil::IsTaxname(src_objs.front());
2543  // delete source field
2544  NON_CONST_ITERATE(CMQueryNodeValue::TObs, it, src_objs) {
2545  RemoveFieldByName(*it);
2546  }
2547  if (is_taxname) {
2549  }
2550  }
2551 
2552  CCleanup cleanup;
2553  if (dynamic_cast<const CSeq_feat*>(obj.GetPointer())) {
2555  cleanup.BasicCleanup(*seq_feat);
2556  if (seq_feat->IsSetXref()) {
2557  auto gene_xref = seq_feat->GetGeneXref();
2558  is_gene_suppressed_after = gene_xref->IsSuppressed();
2559  if (!is_gene_suppressed_before && is_gene_suppressed_after)
2560  NMacroUtil::RemoveGeneXref(*seq_feat);
2561  }
2562  }
2563  else if (dynamic_cast<const CBioSource*>(obj.GetPointer())) {
2565  cleanup.BasicCleanup(*bsrc);
2566  if (bsrc->IsSetOrg() && bsrc->GetOrg().IsSetDb() && bsrc->GetOrg().GetDb().empty()) {
2567  bsrc->SetOrg().ResetDb();
2568  }
2569  }
2570 
2571  if (m_QualsChangedCount) {
2572  m_DataIter->SetModified();
2574  log << m_DataIter->GetBestDescr() << ": swapped " << m_QualsChangedCount << " qualifiers";
2575  x_LogFunction(log);
2576  }
2577 }
2578 
2580 {
2581  if (m_Args.size() < 2) {
2582  return false;
2583  }
2584 
2585  for (auto& it : m_Args) {
2586  CMQueryNodeValue::EType type = it->GetDataType();
2588  return false;
2589  }
2590  }
2591  return true;
2592 }
2593 
2594 
2596 {
2597  if (index >= m_Args.size())
2598  return false;
2599 
2600  CMQueryNodeValue::EType type = m_Args[index]->GetDataType();
2602  GetFieldsByName(&result, oi, m_Args[index]->GetString());
2603  }
2604  else if (type == CMQueryNodeValue::eObjects) {
2605  result = m_Args[index]->GetObjects();
2606  }
2607  else if (type == CMQueryNodeValue::eRef) {
2608  x_GetObjectsFromRef(result, index);
2609  }
2610 
2611  return (!result.empty());
2612 }
2613 
2615 {
2616  if (index >= m_Args.size())
2617  return false;
2618 
2619  // the field does not have to be set
2620  CMQueryNodeValue::EType type = m_Args[index]->GetDataType();
2622  SetFieldsByName(&result, oi, m_Args[index]->GetString());
2623  }
2624  else {
2625  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
2626  x_SetField(obj, m_Args[++index]->GetString(), result);
2627  }
2628  return (!result.empty());
2629 }
2630 
2631 static void s_SetBioSourceField(CRef<CBioSource> bsrc, CObjectInfo& oi, const string& field_name, CMQueryNodeValue::TObs& dest_objs)
2632 {
2633  if (field_name.empty())
2634  return;
2635 
2636  // check if the field denotes an orgmod or a subsource modifier
2637  if (NMacroUtil::IsBiosourceModifier(field_name)) {
2638  // check if it's a subsource modifier
2641 
2642  CRef<CSubSource> sub_src(new CSubSource());
2643  sub_src->SetSubtype(st);
2644  sub_src->SetName(kEmptyStr);
2645  bsrc->SetSubtype().push_back(sub_src);
2646  CObjectInfo subsrc_oi(sub_src.GetPointer(), sub_src->GetTypeInfo());
2647  dest_objs.push_back(CMQueryNodeValue::SResolvedField(oi, subsrc_oi));
2648  // check if it's an orgmod modifier
2649  }
2652 
2653  CRef<COrgMod> orgmod(new COrgMod());
2654  orgmod->SetSubtype(st);
2655  orgmod->SetSubname(kEmptyStr);
2656  CRef<COrgName> orgname;
2657  if (!bsrc->IsSetOrgname()) {
2658  orgname.Reset(new COrgName());
2659  orgname->SetMod().push_back(orgmod);
2660  bsrc->SetOrg().SetOrgname(*orgname);
2661  }
2662  else {
2663  orgname = Ref(&(bsrc->SetOrg().SetOrgname()));
2664  orgname->SetMod().push_back(orgmod);
2665  }
2666  CObjectInfo parent_mod_oi(orgname.GetPointer(), orgname->GetThisTypeInfo());
2667  CObjectInfo orgmod_oi(orgmod.GetPointer(), orgmod->GetThisTypeInfo());
2668  dest_objs.push_back(CMQueryNodeValue::SResolvedField(parent_mod_oi, orgmod_oi));
2669  }
2670  }
2671  else {
2672  SetFieldsByName(&dest_objs, oi, field_name);
2673  }
2674 }
2675 
2676 static void s_SetFeatField(CRef<CSeq_feat> feat, CObjectInfo& oi,const string& field_name, CMQueryNodeValue::TObs& result)
2677 {
2678  if (field_name.empty())
2679  return;
2680 
2681  if (SetFieldsByName(&result, oi, field_name)) {
2682  return;
2683  }
2684 
2685  CRef<CGb_qual> new_gbqual(new CGb_qual(field_name, kEmptyStr));
2686  feat->SetQual().push_back(new_gbqual);
2687  CObjectInfo gbqual_oi(new_gbqual.GetPointer(), new_gbqual->GetTypeInfo());
2688  result.push_back(CMQueryNodeValue::SResolvedField(oi, gbqual_oi));
2689 }
2690 
2692 {
2693  CObjectInfo oi = m_DataIter->GetEditedObject();
2694  const CBioSource* cbsrc = dynamic_cast<const CBioSource*>(obj.GetPointer());
2695  const CSeq_feat* cfeat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
2696  if (cbsrc) {
2698  return s_SetBioSourceField(Ref(bsrc), oi, field_name, result);
2699  }
2700  if (cfeat) {
2702  return s_SetFeatField(Ref(feat), oi, field_name, result);
2703  }
2704 }
2705 
2706 static string s_GetEnumValue(CObjectInfo& obj)
2707 {
2708  string value;
2710  try {
2712  }
2713  catch (const CException&) {
2715  }
2716  }
2717  return value;
2718 }
2719 
2720 static bool s_SetEnumValue(CObjectInfo& obj, const string& str)
2721 {
2722  bool set = false;
2724  try {
2726  set = true;
2727  }
2728  catch (const CException&) {
2729  // if this fails, try to convert the string to int and assign again
2730  try {
2732  set = true;
2733  }
2734  catch (const CException&) {}
2735  }
2736  }
2737  return set;
2738 }
2739 
2740 
2742 {
2743  if (src.GetTypeFamily() != dest.GetTypeFamily() || src.GetTypeFamily() != eTypeFamilyPrimitive) {
2744  return false;
2745  }
2746 
2747  bool swapped = false;
2749  string tmp = src.GetPrimitiveValueString();
2753  swapped = true;
2754  }
2755  else if (dest.GetPrimitiveValueType() == ePrimitiveValueEnum) {
2756  string dest_value = s_GetEnumValue(dest);
2757  src.SetPrimitiveValueString(dest_value);
2758  swapped = s_SetEnumValue(dest, tmp);
2759  }
2760  }
2761  else if (src.GetPrimitiveValueType() == ePrimitiveValueEnum) {
2762  string tmp = s_GetEnumValue(src);
2764  swapped = s_SetEnumValue(src, dest.GetPrimitiveValueString());
2766  }
2767  else if (dest.GetPrimitiveValueType() == ePrimitiveValueEnum) {
2768  string dest_value = s_GetEnumValue(dest);
2769  swapped = s_SetEnumValue(src, dest_value);
2770  swapped = swapped && s_SetEnumValue(dest, tmp);
2771  }
2772  }
2773 
2774  if (swapped)
2776  return swapped;
2777 }
2778 
2780 {
2781  // swaps primitive values
2782  // both src and dest should be of primitive type
2783  if (src.GetTypeFamily() != dest.GetTypeFamily() || src.GetTypeFamily() != eTypeFamilyPrimitive) {
2784  return false;
2785  }
2786 
2787  switch (src.GetPrimitiveValueType()) {
2788  case ePrimitiveValueBool: {
2789  bool tmp = dest.GetPrimitiveValueBool();
2792  return true;
2793  }
2795  case ePrimitiveValueChar: {
2796  int tmp = dest.GetPrimitiveValueInt();
2799  return true;
2800  }
2801  case ePrimitiveValueReal: {
2802  double tmp = dest.GetPrimitiveValueDouble();
2805  return true;
2806  }
2807  case ePrimitiveValueString: {
2808  string tmp = dest.GetPrimitiveValueString();
2811  return true;
2812  }
2813  case ePrimitiveValueEnum: // to be done
2814  return false;
2815  default:
2816  ;
2817  }
2818  return false;
2819 }
2820 
2822 {
2823  // copy contents of the destination field into the source field
2824  CMQueryNodeValue::TObs::iterator src_it = src_objs.begin();
2825  CMQueryNodeValue::TObs::iterator dest_it = dest_objs.begin();
2826 
2827  while (src_it != src_objs.end() && dest_it != dest_objs.end()) {
2828  CMQueryNodeValue::TObs src_prim_objs;
2829  NMacroUtil::GetPrimitiveObjInfosWithContainers(src_prim_objs, *src_it);
2830  CMQueryNodeValue::TObs dest_prim_objs;
2831  NMacroUtil::GetPrimitiveObjInfosWithContainers(dest_prim_objs, *dest_it);
2832 
2833  if (dest_prim_objs.empty() && dest_it->field.GetTypeFamily() == eTypeFamilyContainer) {
2834  // add new element when the container is empty
2835  CObjectInfo new_oi(dest_it->field.AddNewElement());
2836  dest_prim_objs.push_back(CMQueryNodeValue::SResolvedField(dest_it->field, new_oi));
2837  }
2838  x_CopyFields(src_prim_objs.front().field, dest_prim_objs.front().field);
2839 
2840  ++src_it;
2841  ++dest_it;
2842  }
2843 }
2844 
2846 {
2847  if (src.GetTypeFamily() != dest.GetTypeFamily() || src.GetTypeFamily() != eTypeFamilyPrimitive) {
2848  return false;
2849  }
2850 
2851  string src_val;
2853  src_val = src.GetPrimitiveValueString();
2854  }
2855  else if (src.GetPrimitiveValueType() == ePrimitiveValueEnum) { // codon-start
2856  src_val = NStr::IntToString(src.GetPrimitiveValueInt());
2857  }
2858 
2859  string dest_val = dest.GetPrimitiveValueString();
2860  if (edit::AddValueToString(dest_val, src_val, edit::eExistingText_replace_old)) {
2861  return SetQualStringValue(dest, dest_val);
2862  }
2863  return false;
2864 }
2865 
2866 
2867 /// class CMacroFunction_SwapRelFeatQual
2868 /// SwapFeatureQual([src_obj,] src_field, dest_feat_subtype, dest_field, update_mrna);
2869 ///
2871 
2873 {
2874  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
2875  const CSeq_feat* src_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
2876  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
2877  if (!src_feat || !scope)
2878  return;
2879 
2880  size_t src_index = 0, dest_index = 1;
2881  if (m_Args.size() == 5) {
2882  dest_index = 2;
2883  }
2884  if (m_Args[dest_index]->GetString().empty() || m_Args[dest_index + 1]->GetString().empty())
2885  return;
2886 
2887  const string& dest_feattype = m_Args[dest_index]->GetString();
2888  const string& dest_field = m_Args[dest_index + 1]->GetString();
2889  const string src_field = (m_Args[src_index]->GetDataType() == CMQueryNodeValue::eString) ?
2890  m_Args[src_index]->GetString() : kEmptyStr;
2891 
2892  // reset members
2893  m_ConstDestFeat.Reset(nullptr);
2894  m_EditDestFeat.Reset(nullptr);
2895  m_CreatedFeat.Reset(nullptr);
2896 
2897  // check that at least one of the fields exist
2898  CObjectInfo oi = m_DataIter->GetEditedObject();
2899  CMQueryNodeValue::TObs src_objs;
2900  CMQueryNodeValue::TObs dest_objs;
2902 
2903  bool src_set = x_DoFieldsExist(oi, src_objs, src_index);
2904  if (IstRNAProductField(*src_feat, src_field)) {
2905  src_set = !src_feat->GetData().GetRna().GetRnaProductName().empty();
2906  }
2907  bool dest_set = x_DoDestFeatFieldsExist(*src_feat, dest_objs, dest_feattype, dest_field);
2908 
2909  if (!src_set && !dest_set)
2910  return;
2911 
2912  if (!src_set) {
2913  x_SetFields(oi, src_objs, src_index);
2914  }
2915  if (!dest_set) {
2916  x_SetOrCreateDestFeatFields(*src_feat, dest_objs, dest_index + 1);
2917  }
2918 
2919  if (src_set && dest_set) {
2920  CMQueryNodeValue::TObs::iterator src_it = src_objs.begin();
2921  CMQueryNodeValue::TObs::iterator dest_it = dest_objs.begin();
2922 
2923  while (src_it != src_objs.end() && dest_it != dest_objs.end()) {
2924  CMQueryNodeValue::TObs src_prim_objs;
2925  NMacroUtil::GetPrimitiveObjInfosWithContainers(src_prim_objs, *src_it);
2926  CMQueryNodeValue::TObs dest_prim_objs;
2927  NMacroUtil::GetPrimitiveObjInfosWithContainers(dest_prim_objs, *dest_it);
2928  if (dest_prim_objs.empty() && dest_it->field.GetTypeFamily() == eTypeFamilyContainer) {
2929  // add new element when the container is empty
2930  CObjectInfo new_oi(dest_it->field.AddNewElement());
2931  dest_prim_objs.push_back(CMQueryNodeValue::SResolvedField(dest_it->field, new_oi));
2932  }
2933  x_SwapFields(src_prim_objs.front().field, dest_prim_objs.front().field);
2934 
2935  ++src_it;
2936  ++dest_it;
2937  }
2938 
2939  if (m_EditDestFeat && IstRNAProductField(*m_EditDestFeat, dest_field)) {
2940  while (src_it != src_objs.end()) {
2941  CMQueryNodeValue::TObs src_prim_objs;
2942  NMacroUtil::GetPrimitiveObjInfosWithContainers(src_prim_objs, *src_it);
2943 
2944  string dest_str = m_EditDestFeat->GetData().GetRna().GetRnaProductName();
2945  CObjectInfo src = src_prim_objs.front().field;
2946 
2948  string tmp = src.GetPrimitiveValueString();
2949  src.SetPrimitiveValueString(dest_str);
2950  string remainder;
2951  m_EditDestFeat->SetData().SetRna().SetRnaProductName(tmp, remainder);
2952  m_QualsChangedCount++;
2953  }
2954  ++src_it;
2955  }
2956  }
2957  else if (IstRNAProductField(*src_feat, src_field)) {
2958  while (dest_it != dest_objs.end()) {
2959  CMQueryNodeValue::TObs dest_prim_objs;
2960  NMacroUtil::GetPrimitiveObjInfosWithContainers(dest_prim_objs, *dest_it);
2961  if (dest_prim_objs.empty() && dest_it->field.GetTypeFamily() == eTypeFamilyContainer) {
2962  // add new element when the container is empty
2963  CObjectInfo new_oi(dest_it->field.AddNewElement());
2964  dest_prim_objs.push_back(CMQueryNodeValue::SResolvedField(dest_it->field, new_oi));
2965  }
2966 
2967  string src_str = src_feat->GetData().GetRna().GetRnaProductName();
2968  CObjectInfo d = dest_prim_objs.front().field;
2970  string tmp = d.GetPrimitiveValueString();
2971  d.SetPrimitiveValueString(src_str);
2972 
2973  string remainder;
2974  seq_feat->SetData().SetRna().SetRnaProductName(tmp, remainder);
2975  m_QualsChangedCount++;
2976  }
2977  ++dest_it;
2978  }
2979  }
2980  }
2981  else if (!src_set) {
2982  // copy destination field into the source field
2983  x_CopyFields(dest_objs, src_objs);
2984 
2985  if (IstRNAProductField(*seq_feat, src_field)) {
2986  CMQueryNodeValue::TObs::iterator dest_it = dest_objs.begin();
2987 
2988  while (dest_it != dest_objs.end()) {
2989  CMQueryNodeValue::TObs dest_prim_objs;
2990  NMacroUtil::GetPrimitiveObjInfosWithContainers(dest_prim_objs, *dest_it);
2991 
2992  CObjectInfo d = dest_prim_objs.front().field;
2993  string dest_val;
2995  dest_val = d.GetPrimitiveValueString();
2996  }
2997  else if (d.GetPrimitiveValueType() == ePrimitiveValueEnum) { // codon-start
2998  dest_val = NStr::IntToString(d.GetPrimitiveValueInt());
2999  }
3000 
3001  string remainder;
3002  seq_feat->SetData().SetRna().SetRnaProductName(dest_val, remainder);
3003  m_QualsChangedCount++;
3004  ++dest_it;
3005  }
3006  }
3007 
3008  if (m_EditDestFeat && IstRNAProductField(*m_EditDestFeat, dest_field)) {
3009  CMQueryNodeValue::TObs::iterator src_it = src_objs.begin();
3010 
3011  while (src_it != src_objs.end()) {
3012  CMQueryNodeValue::TObs src_prim_objs;
3013  NMacroUtil::GetPrimitiveObjInfosWithContainers(src_prim_objs, *src_it);
3014 
3015  string rna_str = m_EditDestFeat->GetData().GetRna().GetRnaProductName();
3016  CObjectInfo src = src_prim_objs.front().field;
3017  src.SetPrimitiveValueString(rna_str);
3018  m_QualsChangedCount++;
3019  ++src_it;
3020  }
3021  }
3022 
3023  // delete destination field
3024  if (m_EditDestFeat && IstRNAProductField(*m_EditDestFeat, dest_field)) {
3025  string remainder;
3026  m_EditDestFeat->SetData().SetRna().SetRnaProductName(kEmptyStr, remainder);
3027  }
3028 
3029  NON_CONST_ITERATE(CMQueryNodeValue::TObs, it, dest_objs) {
3030  if (it->parent.GetName() == "Gb-qual" && m_EditDestFeat) {
3031  const string& qual_name = m_Args[m_Args.size() - 2]->GetString();
3032  m_EditDestFeat->RemoveQualifier(qual_name);
3033  }
3034  else {
3035  RemoveFieldByName(*it);
3036  }
3037  }
3038  }
3039  else if (!dest_set) {
3040  // copy source field into the destination field
3041  x_CopyFields(src_objs, dest_objs);
3042 
3043  if (m_EditDestFeat && IstRNAProductField(*m_EditDestFeat, dest_field)) {
3044  CMQueryNodeValue::TObs::iterator src_it = src_objs.begin();
3045 
3046  while (src_it != src_objs.end()) {
3047  CMQueryNodeValue::TObs src_prim_objs;
3048  NMacroUtil::GetPrimitiveObjInfosWithContainers(src_prim_objs, *src_it);
3049 
3050  CObjectInfo src = src_prim_objs.front().field;
3051  string src_val;
3053  src_val = src.GetPrimitiveValueString();
3054  }
3055  else if (src.GetPrimitiveValueType() == ePrimitiveValueEnum) { // codon-start
3056  src_val = NStr::IntToString(src.GetPrimitiveValueInt());
3057  }
3058 
3059  string remainder;
3060  m_EditDestFeat->SetData().SetRna().SetRnaProductName(src_val, remainder);
3061  m_QualsChangedCount++;
3062  ++src_it;
3063  }
3064  }
3065 
3066  if (IstRNAProductField(*seq_feat, src_field)) {
3067  CMQueryNodeValue::TObs::iterator dest_it = dest_objs.begin();
3068 
3069  while (dest_it != dest_objs.end()) {
3070  CMQueryNodeValue::TObs dest_prim_objs;
3071  NMacroUtil::GetPrimitiveObjInfosWithContainers(dest_prim_objs, *dest_it);
3072 
3073  string rna_str = seq_feat->GetData().GetRna().GetRnaProductName();
3074  CObjectInfo d = dest_prim_objs.front().field;
3075  d.SetPrimitiveValueString(rna_str);
3076  m_QualsChangedCount++;
3077  ++dest_it;
3078  }
3079  }
3080 
3081  // delete source field
3082  if (IstRNAProductField(*seq_feat, src_field)) {
3083  string remainder;
3084  seq_feat->SetData().SetRna().SetRnaProductName(kEmptyStr, remainder);
3085  }
3086  NON_CONST_ITERATE(CMQueryNodeValue::TObs, it, src_objs) {
3087  RemoveFieldByName(*it);
3088  }
3089  }
3090 
3091  bool update_mrna = (m_Args.back()->GetDataType() == CMQueryNodeValue::eBool) ? m_Args.back()->GetBool() : false;
3092 
3093  CCleanup cleanup;
3094  cleanup.BasicCleanup(*seq_feat);
3095  if (m_EditDestFeat) {
3096  cleanup.BasicCleanup(*m_EditDestFeat);
3097  }
3098  else if (m_CreatedFeat) {
3099  cleanup.BasicCleanup(*m_CreatedFeat);
3100  }
3101 
3102  if (m_QualsChangedCount) {
3103  m_DataIter->SetModified();
3105  log << m_DataIter->GetBestDescr() << ": swapped " << m_QualsChangedCount << " qualifiers";
3106 
3108  if (m_ConstDestFeat && m_EditDestFeat) {
3109  cmd.Reset(new CCmdComposite("Change Related feature"));
3110  CSeq_feat_Handle fh = scope->GetSeq_featHandle(*m_ConstDestFeat);
3111  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *m_EditDestFeat)));
3112  if (update_mrna && m_EditDestFeat->GetData().GetSubtype() == CSeqFeatData::eSubtype_prot) {
3113  string message;
3114  CRef<CCmdComposite> upd_cmd = UpdatemRNAProduct(*m_EditDestFeat, *scope, message);
3115  if (upd_cmd) {
3116  cmd->AddCommand(*upd_cmd);
3117  log << ", " << message;
3118  }
3119  }
3120  }
3121  else if (m_CreatedFeat) {
3122  cmd.Reset(new CCmdComposite("Create feature"));
3123  CBioseq_Handle bsh = scope->GetBioseqHandle(m_CreatedFeat->GetLocation());
3124  cmd->AddCommand(*CRef<CCmdCreateFeatBioseq>(new CCmdCreateFeatBioseq(bsh, *m_CreatedFeat)));
3125  if (update_mrna && m_CreatedFeat->GetData().GetSubtype() == CSeqFeatData::eSubtype_prot) {
3126  string message;
3127  CRef<CCmdComposite> upd_cmd = UpdatemRNAProduct(*m_CreatedFeat, *scope, message);
3128  if (upd_cmd) {
3129  cmd->AddCommand(*upd_cmd);
3130  log << ", " << message;
3131  }
3132  }
3133  }
3134  if (cmd) {
3135  m_DataIter->RunCommand(cmd, m_CmdComposite);
3136  }
3137 
3138  if (update_mrna && src_feat->GetData().GetSubtype() == CSeqFeatData::eSubtype_prot) {
3140  string prot_product = edit_feat->GetData().GetProt().GetName().front();
3141  CRef<CCmdComposite> upd_cmd = UpdatemRNAProduct(prot_product, obj, *scope);
3142  if (upd_cmd) {
3143  m_DataIter->RunCommand(upd_cmd, m_CmdComposite);
3144  log << ", applied " + prot_product + " to mRNA product name ";
3145  }
3146  }
3147  x_LogFunction(log);
3148  }
3149 }
3150 
3152  const CSeq_feat& src_feat, CMQueryNodeValue::TObs& result, const string& dest_feattype, const string& dest_field)
3153 {
3154  CSeqFeatData::ESubtype target_feature = NMacroUtil::GetFeatSubtype(dest_feattype);
3155  NMacroUtil::TVecFeatList feat_list = edit::GetRelatedFeatures(src_feat, target_feature, Ref(&(m_DataIter->GetSEH().GetScope())));
3156 
3157  if (!feat_list.empty() && feat_list.size() == 1) {
3158  m_ConstDestFeat.Reset(feat_list.front());
3160  m_EditDestFeat->Assign(*feat_list.front());
3161  GetFeatDestinationField(m_EditDestFeat, dest_field, result);
3162 
3163  if (IstRNAProductField(*m_EditDestFeat, dest_field)) {
3164  return (!m_EditDestFeat->GetData().GetRna().GetRnaProductName().empty());
3165  // it might return true but the output argument results is empty!
3166  }
3167  }
3168  return (!result.empty());
3169 }
3170 
3172 {
3173  if (index >= m_Args.size())
3174  return;
3175  const string& dest_field = m_Args[index]->GetString();
3176 
3178  if (!SetFeatDestinationField(m_EditDestFeat, dest_field, result)) {
3179  return;
3180  }
3181  }
3182  else {
3183  // create a new feature
3184  m_CreatedFeat = CreateNewRelatedFeature(src_feat, dest_field, m_DataIter->GetSEH().GetScope());
3185  if (!SetFeatDestinationField(m_CreatedFeat, dest_field, result)) {
3186  return;
3187  }
3188 
3189  if (src_feat.GetData().IsCdregion() && src_feat.IsSetXref() && m_CreatedFeat->GetData().IsProt()) {
3190  CObjectInfo oi = m_DataIter->GetEditedObject();
3192  NON_CONST_ITERATE(CSeq_feat::TXref, it, edit_feat->SetXref()) {
3193  if ((*it)->IsSetData() && (*it)->GetData().IsProt()) {
3194  m_CreatedFeat->SetData().SetProt().Assign((*it)->GetData().GetProt());
3195  edit_feat->SetXref().erase(it);
3196  break;
3197  }
3198  }
3199  if (edit_feat->GetXref().empty()) {
3200  edit_feat->ResetXref();
3201  }
3202  }
3203  }
3204 }
3205 
3207 {
3208  if (m_Args.size() < 4 || m_Args.size() > 5) {
3209  return false;
3210  }
3211 
3212  bool first_ok = (m_Args[0]->IsString() || m_Args[0]->AreObjects() || m_Args[0]->IsRef());
3213  if (!first_ok) {
3214  return false;
3215  }
3216  for (size_t index = 1; index < m_Args.size() - 1; ++index) {
3217  if (!m_Args[index]->IsString()) {
3218  return false;
3219  }
3220  }
3221  return (m_Args.back()->IsBool());
3222 }
3223 
3224 
3225 ///////////////////////////////////////////////////////////////////////////////
3226 /// class CMacroFunction_ConvertFeatQual
3227 /// ConvertFeatureQual(src_field, dest_feature_type, dest_feature_field, capitalization, strip_name, update_mrna, existing_text_opt, delimiter)
3228 /// The last parameter is optional
3229 /// The function will NOT delete the src_field.
3230 /// To delete the src_field, use RemoveQual() function
3231 /// The related mRNA is only updated if the action is successful and the destination feature is protein
3232 ///
3235 {
3236  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
3237  const CSeq_feat* src_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
3238  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
3239  if (!src_feat || !scope)
3240  return;
3241 
3242  const string& dest_field = m_Args[2]->GetString();
3243  if (dest_field.empty())
3244  return;
3245 
3246  CObjectInfo oi = m_DataIter->GetEditedObject();
3247  CMQueryNodeValue::TObs src_objs;
3248  if (!x_GetSourceFields(oi, 0, src_objs))
3249  return;
3250 
3251  // the destination field can be set at this point
3252  CSeqFeatData::ESubtype target_feature = NMacroUtil::GetFeatSubtype(m_Args[1]->GetString());
3253  NMacroUtil::TVecFeatList feat_list = edit::GetRelatedFeatures(*src_feat, target_feature, scope);
3254  CMQueryNodeValue::TObs dest_objs;
3255  bool changed = false, created = false;
3256  CRef<CSeq_feat> dest_feat;
3257  CSeq_feat_Handle fh;
3258  if (!feat_list.empty() && feat_list.size() == 1) {
3259  dest_feat.Reset(new CSeq_feat);
3260  dest_feat->Assign(*feat_list.front());
3261  if (!SetFeatDestinationField(dest_feat, dest_field, dest_objs)) {
3262  return;
3263  }
3264  fh = scope->GetSeq_featHandle(*feat_list.front());
3265  changed = true;
3266  }
3267  else {
3268  // new feature
3269  dest_feat = CreateNewRelatedFeature(*src_feat, dest_field, *scope);
3270  if (!dest_feat) return;
3271  if (!SetFeatDestinationField(dest_feat, dest_field, dest_objs)) {
3272  return;
3273  }
3274  created = true;
3275  if (src_feat->GetData().IsCdregion() && src_feat->IsSetXref() && dest_feat->GetData().IsProt()) {
3277  NON_CONST_ITERATE(CSeq_feat::TXref, it, edit_feat->SetXref()) {
3278  if ((*it)->IsSetData() && (*it)->GetData().IsProt()) {
3279  dest_feat->SetData().SetProt().Assign((*it)->GetData().GetProt());
3280  edit_feat->SetXref().erase(it);
3281  break;
3282  }
3283  }
3284  if (edit_feat->GetXref().empty()) {
3285  edit_feat->ResetXref();
3286  }
3287  }
3288  }
3289 
3290  size_t index = 3;
3291  const string& capitalization = m_Args[index]->GetString();
3292  //bool strip_name = m_Args[++index]->GetBool();
3293  //strip_name = false; // this option is not implemented (it's false by default)
3294  ++index;
3295  bool update_mrna = m_Args[++index]->GetBool();
3296  const string& action_type = m_Args[++index]->GetString();
3297  string delimiter = (++index < m_Args.size()) ? m_Args[index]->GetString() : kEmptyStr;
3298 
3301 
3302  if (IstRNAProductField(*dest_feat, dest_field)) {
3303  for (auto&& it : src_objs) {
3304  CMQueryNodeValue::TObs src_prim_objs;
3305  NMacroUtil::GetPrimitiveObjectInfos(src_prim_objs, it);
3306 
3307  CObjectInfo src = src_prim_objs.front().field;
3308  string src_val = x_GetSourceString(src);
3309 
3310  string remainder;
3311  dest_feat->SetData().SetRna().SetRnaProductName(src_val, remainder);
3313  }
3314  }
3315  else {
3316  ChangeFields(src_objs, dest_objs);
3317  }
3318 
3319  if (m_QualsChangedCount) {
3320  m_DataIter->SetModified();
3322  log << m_DataIter->GetBestDescr() << ": converted " << m_QualsChangedCount << " qualifiers";
3323 
3325  if (changed && fh) {
3326  cmd.Reset(new CCmdComposite("Change Related feature"));
3327  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *dest_feat)));
3328  }
3329  else if (created) {
3330  cmd.Reset(new CCmdComposite("Create feature"));
3331  CBioseq_Handle bsh = scope->GetBioseqHandle(dest_feat->GetLocation());
3332  cmd->AddCommand(*CRef<CCmdCreateFeatBioseq>(new CCmdCreateFeatBioseq(bsh, *dest_feat)));
3333  }
3334 
3335  if (update_mrna) {
3336  if (dest_feat->GetData().GetSubtype() == CSeqFeatData::eSubtype_prot) {
3337  string message;
3338  CRef<CCmdComposite> upd_cmd = UpdatemRNAProduct(*dest_feat, *scope, message);
3339  if (upd_cmd) {
3340  cmd->AddCommand(*upd_cmd);
3341  log << ", " << message;
3342  }
3343  }
3344  else if(src_feat->GetData().GetSubtype() == CSeqFeatData::eSubtype_prot) {
3346  string prot_product = edit_feat->GetData().GetProt().GetName().front();
3347  CRef<CCmdComposite> upd_cmd = UpdatemRNAProduct(prot_product, obj, *scope);
3348  if (upd_cmd) {
3349  cmd->AddCommand(*upd_cmd);
3350  log << ", applied " + prot_product + " to mRNA product name ";
3351  }
3352  }
3353  }
3354  m_DataIter->RunCommand(cmd, m_CmdComposite);
3355  x_LogFunction(log);
3356  }
3357 }
3358 
3360 {
3361  if (m_Args.size() < 7 || m_Args.size() > 8)
3362  return false;
3363 
3364  if (!( m_Args[0]->IsString() || m_Args[0]->AreObjects() || m_Args[0]->IsRef()))
3365  return false;
3366 
3367  for (size_t index = 1; index < m_Args.size(); ++index) {
3368  auto type = (index != 4 && index != 5) ? CMQueryNodeValue::eString : CMQueryNodeValue::eBool;
3369  if (m_Args[index]->GetDataType() != type)
3370  return false;
3371  }
3372  return true;
3373 }
3374 
3375 
3376 ///////////////////////////////////////////////////////////////////////////////
3377 // CMacroFunction_ConvertRNARelQual
3378 /// ConvertRnaRelQual('rna'/'gene', src_field, 'gene'/'rna', dest_field, capitalization, strip_name, existing_text_opt, delimiter)
3379 /// The last parameter is optional
3380 /// Use this function when you need to convert from/to an RNA qualifier and a Gene qualifier
3381 /// Don't use this function to convert between two RNA qualifiers
3384 {
3385  // The iterator should be an RNA feature
3386  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
3387  const CSeq_feat* rna_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
3388  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
3389  if (!rna_feat || !scope)
3390  return;
3391 
3392  if (rna_feat->IsSetData() && !rna_feat->GetData().IsRna())
3393  return;
3394 
3395  const string& src_feat = m_Args[0]->GetString();
3396  const string& dest_feat = m_Args[2]->GetString();
3397  if (src_feat == "rna" && src_feat == dest_feat)
3398  return;
3399 
3400  if ((src_feat != "rna" && src_feat != "gene") || (dest_feat != "rna" && dest_feat != "gene"))
3401  return;
3402 
3403  size_t index = 4;
3404  const string& capitalization = m_Args[index]->GetString();
3405  //bool strip_name = m_Args[++index]->GetBool();
3406  //strip_name = false; // this option is not implemented (it's false by default)
3407  ++index;
3408  const string& action_type = m_Args[++index]->GetString();
3409  string delimiter = (++index < m_Args.size()) ? m_Args[index]->GetString() : kEmptyStr;
3412 
3413  if (src_feat == "rna" && dest_feat == "gene") {
3414  CObjectInfo oi = m_DataIter->GetEditedObject();
3415  CMQueryNodeValue::TObs src_objs;
3416  if (!x_GetSourceFields(oi, 1, src_objs))
3417  return;
3418 
3419  const string dest_field = m_Args[3]->GetString();
3420  // the destination field can be set at this point
3422  CMQueryNodeValue::TObs dest_objs;
3423  bool changed = false, created = false;
3424  CRef<CSeq_feat> dest_feat;
3425  CSeq_feat_Handle fh;
3426  if (!feat_list.empty() && feat_list.size() == 1) {
3427  dest_feat.Reset(new CSeq_feat);
3428  dest_feat->Assign(*feat_list.front());
3429  if (!SetFeatDestinationField(dest_feat, dest_field, dest_objs)) {
3430  return;
3431  }
3432  fh = scope->GetSeq_featHandle(*feat_list.front());
3433  changed = true;
3434  }
3435  else {
3436  // new feature
3437  dest_feat = CreateNewRelatedFeature(*rna_feat, dest_field, *scope);
3438  if (!dest_feat) return;
3439  if (!SetFeatDestinationField(dest_feat, dest_field, dest_objs)) {
3440  return;
3441  }
3442  created = true;
3443  }
3444 
3445  ChangeFields(src_objs, dest_objs);
3446 
3447  if (m_QualsChangedCount) {
3449  if (changed && fh) {
3450  cmd.Reset(new CCmdComposite("Change Related feature"));
3451  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *dest_feat)));
3452  }
3453  else if (created) {
3454  cmd.Reset(new CCmdComposite("Create feature"));
3455  CBioseq_Handle bsh = scope->GetBioseqHandle(dest_feat->GetLocation());
3456  cmd->AddCommand(*CRef<CCmdCreateFeatBioseq>(new CCmdCreateFeatBioseq(bsh, *dest_feat)));
3457  }
3458 
3459  m_DataIter->RunCommand(cmd, m_CmdComposite);
3461  log << m_DataIter->GetBestDescr() << ": converted " << m_QualsChangedCount << " qualifiers";
3462  x_LogFunction(log);
3463  }
3464  }
3465  else if (src_feat == "gene" && dest_feat == "gene") {
3467  CMQueryNodeValue::TObs src_objs, dest_objs;
3468 
3469  CRef<CSeq_feat> gene_feat;
3470  CSeq_feat_Handle fh;
3471  if (!feat_list.empty() && feat_list.size() == 1) {
3472  gene_feat.Reset(new CSeq_feat);
3473  gene_feat->Assign(*feat_list.front());
3474 
3475  CObjectInfo gene_oi(gene_feat.GetPointer(), gene_feat->GetThisTypeInfo());
3476  if (!x_GetSourceFields(gene_oi, 1, src_objs))
3477  return;
3478 
3479  if (!x_GetDestFields(gene_oi, 3, dest_objs))
3480  return;
3481 
3482  fh = scope->GetSeq_featHandle(*feat_list.front());
3483  }
3484  else {
3485  // no gene was found
3486  return;
3487  }
3488 
3489  ChangeFields(src_objs, dest_objs);
3490 
3491  if (m_QualsChangedCount) {
3493  if (fh) {
3494  cmd.Reset(new CCmdComposite("Change Related feature"));
3495  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *gene_feat)));
3496  }
3497 
3498  m_DataIter->RunCommand(cmd, m_CmdComposite);
3500  log << m_DataIter->GetBestDescr() << ": converted " << m_QualsChangedCount << " qualifiers";
3501  x_LogFunction(log);
3502  }
3503  }
3504  else if (src_feat == "gene" && dest_feat == "rna") {
3505 
3507  CMQueryNodeValue::TObs src_objs, dest_objs;
3508  CRef<CSeq_feat> gene_feat;
3509  if (!feat_list.empty() && feat_list.size() == 1) {
3510  gene_feat.Reset(new CSeq_feat);
3511  gene_feat->Assign(*feat_list.front());
3512 
3513  CObjectInfo gene_oi(gene_feat.GetPointer(), gene_feat->GetThisTypeInfo());
3514  if (!x_GetSourceFields(gene_oi, 1, src_objs))
3515  return;
3516  }
3517  else {
3518  // no gene was found
3519  return;
3520  }
3521 
3522  CObjectInfo oi = m_DataIter->GetEditedObject();
3523  if (!x_GetDestFields(oi, 3, dest_objs))
3524  return;
3525 
3527  if (m_Args[3]->IsString() && NStr::EndsWith(m_Args[3]->GetString(), "::product")) {
3528  for (auto&& it : src_objs) {
3529  CMQueryNodeValue::TObs src_prim_objs;
3530  NMacroUtil::GetPrimitiveObjectInfos(src_prim_objs, it);
3531 
3532  CObjectInfo src = src_prim_objs.front().field;
3533  string src_val = x_GetSourceString(src);
3534 
3535  string remainder;
3536  edit_feat->SetData().SetRna().SetRnaProductName(src_val, remainder);
3538  }
3539  }
3540  else {
3541  ChangeFields(src_objs, dest_objs);
3542  }
3543 
3544  if (m_QualsChangedCount) {
3545  m_DataIter->SetModified();
3547  log << m_DataIter->GetBestDescr() << ": converted " << m_QualsChangedCount << " qualifiers";
3548  x_LogFunction(log);
3549  }
3550  }
3551 }
3552 
3554 {
3555  auto nr_args = m_Args.size();
3556  if (nr_args < 7 || nr_args > 8)
3557  return false;
3558 
3559  if (!m_Args[0]->IsString() || !m_Args[2]->IsString())
3560  return false;
3561 
3562  for (size_t index = 1; index < 4; index += 2) {
3563  if (!(m_Args[index]->IsString() || m_Args[index]->AreObjects() || m_Args[index]->IsRef()))
3564  return false;
3565  }
3566 
3567  for (size_t index = 4; index < nr_args; ++index) {
3568  if (index != 5 && !m_Args[index]->IsString())
3569  return false;
3570  }
3571  return (m_Args[5]->IsBool());
3572 }
3573 
3574 ///////////////////////////////////////////////////////////////////////////////
3575 /// class CMacroFunction_ParseStringQual - used when parsing SeqId
3576 /// ParseStringQual(from_field, to_field, capitalization, existing_text_opt, delimiter) // when all the text should be copied
3577 /// Last parameter is optional
3578 ///
3581 {
3582  CObjectInfo oi = m_DataIter->GetEditedObject();
3583  CMQueryNodeValue::TObs src_objs;
3584  size_t index = 0;
3585  if (!x_GetSourceFields(oi, index, src_objs))
3586  return;
3587 
3588  CMQueryNodeValue::TObs dest_objs;
3589  if (!x_GetDestFields(oi, ++index, dest_objs))
3590  return;
3591 
3592  const string& capitalization = m_Args[++index]->GetString();
3593  const string& action_type = m_Args[++index]->GetString();
3594  string delimiter = (++index < m_Args.size()) ? m_Args[index]->GetString() : kEmptyStr;
3595 
3598 
3599  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
3600  const CSeq_feat* src_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
3601  if (src_feat && m_Args[1]->IsString() && NStr::EndsWith(m_Args[1]->GetString(), "::product")) {
3603  for (auto&& it : src_objs) {
3604  CMQueryNodeValue::TObs src_prim_objs;
3605  NMacroUtil::GetPrimitiveObjectInfos(src_prim_objs, it);
3606 
3607  CObjectInfo src = src_prim_objs.front().field;
3608  string src_val = x_GetSourceString(src);
3609 
3610  string remainder;
3611  edit_feat->SetData().SetRna().SetRnaProductName(src_val, remainder);
3613  }
3614  }
3615  else {
3616  ChangeFields(src_objs, dest_objs);
3617  }
3618  if (m_QualsChangedCount) {
3619  if (!dest_objs.empty()) {
3620  NMacroUtil::CleanupForTaxnameChange(dest_objs.front(), oi);
3621  }
3622  m_DataIter->SetModified();
3624  log << m_DataIter->GetBestDescr() << ": parsed " << m_QualsChangedCount << " qualifiers";
3625  x_LogFunction(log);
3626  }
3627 }
3628 
3630 {
3631  if (dest.GetTypeFamily() != eTypeFamilyPrimitive) {
3632  return false;
3633  }
3634 
3636 
3637  string src_val = x_GetSourceString(src);
3638  string dest_val = dest.GetPrimitiveValueString();
3639  if (edit::AddValueToString(dest_val, src_val, m_ExistingText)) {
3640  return SetQualStringValue(dest, dest_val);
3641  }
3642  return false;
3643 }
3644 
3646 {
3647  string src_val = IOperateOnTwoQuals::x_GetSourceString(src);
3648  // it copies the whole string
3649  CSeq_entry_Handle seh = m_DataIter->GetSEH();
3650  FixCapitalizationInString(seh, src_val, m_CapChange);
3651  return src_val;
3652 }
3653 
3655 {
3656  size_t as = m_Args.size();
3657  if (as < 1 || as > 5) {
3658  return false;
3659  }
3660  for (size_t i = 0; i < 2; ++i) {
3661  if (!(m_Args[i]->IsString() || m_Args[i]->AreObjects() || m_Args[i]->IsRef()))
3662  return false;
3663  }
3664  for (size_t index = 2; index < as; ++index) {
3665  if (!m_Args[index]->IsString()) {
3666  return false;
3667  }
3668  }
3669  return true;
3670 }
3671 
3672 
3673 ///////////////////////////////////////////////////////////////////////////////
3674 /// class CMacroFunction_ParseFeatQual
3675 /// ParseFeatureQual(src_field, dest_feature_type, dest_feature_field, capitalization, update_mrna, existing_text_opt, delimiter)
3676 /// The last parameter is optional
3677 /// The related mRNA is only updated if the action is successful and the destination feature is protein
3678 ///
3681 {
3682  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
3683  const CSeq_feat* src_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
3684  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
3685  if (!src_feat || !scope)
3686  return;
3687 
3688  const string& dest_field = m_Args[2]->GetString();
3689  if (dest_field.empty())
3690  return;
3691 
3692  CObjectInfo oi = m_DataIter->GetEditedObject();
3693  CMQueryNodeValue::TObs src_objs;
3694  if (!x_GetSourceFields(oi, 0, src_objs))
3695  return;
3696 
3697  // the destination field can be set at this point
3698  CSeqFeatData::ESubtype target_feature = NMacroUtil::GetFeatSubtype(m_Args[1]->GetString());
3699  NMacroUtil::TVecFeatList feat_list = edit::GetRelatedFeatures(*src_feat, target_feature, scope);
3700  CMQueryNodeValue::TObs dest_objs;
3701  bool changed = false, created = false;
3702  CRef<CSeq_feat> dest_feat;
3703  CSeq_feat_Handle fh;
3704  if (!feat_list.empty() && feat_list.size() == 1) {
3705  dest_feat.Reset(new CSeq_feat);
3706  dest_feat->Assign(*feat_list.front());
3707  if (!SetFeatDestinationField(dest_feat, dest_field, dest_objs)) {
3708  return;
3709  }
3710  fh = scope->GetSeq_featHandle(*feat_list.front());
3711  changed = true;
3712  }
3713  else {
3714  // new feature
3715  dest_feat = CreateNewRelatedFeature(*src_feat, dest_field, *scope);
3716  if (!dest_feat) return;
3717  if (!SetFeatDestinationField(dest_feat, dest_field, dest_objs)) {
3718  return;
3719  }
3720  created = true;
3721  if (src_feat->GetData().IsCdregion() && src_feat->IsSetXref() && dest_feat->GetData().IsProt()) {
3723  NON_CONST_ITERATE(CSeq_feat::TXref, it, edit_feat->SetXref()) {
3724  if ((*it)->IsSetData() && (*it)->GetData().IsProt()) {
3725  dest_feat->SetData().SetProt().Assign((*it)->GetData().GetProt());
3726  edit_feat->SetXref().erase(it);
3727  break;
3728  }
3729  }
3730  if (edit_feat->GetXref().empty()) {
3731  edit_feat->ResetXref();
3732  }
3733  }
3734  }
3735 
3736  size_t index = 3;
3737  const string& capitalization = m_Args[index]->GetString();
3738  bool update_mrna = m_Args[++index]->GetBool();
3739  const string& action_type = m_Args[++index]->GetString();
3740  string delimiter = (++index < m_Args.size()) ? m_Args[index]->GetString() : kEmptyStr;
3741 
3744 
3745  if (IstRNAProductField(*dest_feat, dest_field)) {
3746  for (auto&& it : src_objs) {
3747  CMQueryNodeValue::TObs src_prim_objs;
3748  NMacroUtil::GetPrimitiveObjectInfos(src_prim_objs, it);
3749 
3750  CObjectInfo src = src_prim_objs.front().field;
3751  string src_val = x_GetSourceString(src);
3752 
3753  string remainder;
3754  dest_feat->SetData().SetRna().SetRnaProductName(src_val, remainder);
3756  }
3757  }
3758  else {
3759  ChangeFields(src_objs, dest_objs);
3760  }
3761 
3762  if (m_QualsChangedCount) {
3763  m_DataIter->SetModified();
3765  log << m_DataIter->GetBestDescr() << ": parsed " << m_QualsChangedCount << " qualifiers";
3766 
3768  if (changed && fh) {
3769  cmd.Reset(new CCmdComposite("Change Related feature"));
3770  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *dest_feat)));
3771  }
3772  else if (created) {
3773  cmd.Reset(new CCmdComposite("Create feature"));
3774  CBioseq_Handle bsh = scope->GetBioseqHandle(dest_feat->GetLocation());
3775  cmd->AddCommand(*CRef<CCmdCreateFeatBioseq>(new CCmdCreateFeatBioseq(bsh, *dest_feat)));
3776  }
3777 
3778  if (update_mrna) {
3779  if (dest_feat->GetData().GetSubtype() == CSeqFeatData::eSubtype_prot) {
3780  string message;
3781  CRef<CCmdComposite> upd_cmd = UpdatemRNAProduct(*dest_feat, *scope, message);
3782  if (upd_cmd) {
3783  cmd->AddCommand(*upd_cmd);
3784  log << ", " << message;
3785  }
3786  }
3787  else if (src_feat->GetData().GetSubtype() == CSeqFeatData::eSubtype_prot) {
3789  string prot_product = edit_feat->GetData().GetProt().GetName().front();
3790  CRef<CCmdComposite> upd_cmd = UpdatemRNAProduct(prot_product, obj, *scope);
3791  if (upd_cmd) {
3792  cmd->AddCommand(*upd_cmd);
3793  log << ", applied " + prot_product + " to mRNA product name ";
3794  }
3795  }
3796  }
3797  m_DataIter->RunCommand(cmd, m_CmdComposite);
3798  x_LogFunction(log);
3799  }
3800 }
3801 
3803 {
3804  if (m_Args.size() < 6 || m_Args.size() > 7)
3805  return false;
3806 
3807  CMQueryNodeValue::EType type = m_Args[0]->GetDataType();
3808  bool first_ok = (type == CMQueryNodeValue::eString)
3810  || (type == CMQueryNodeValue::eRef);
3811  if (!first_ok)
3812  return false;
3813 
3814  for (size_t index = 1; index < m_Args.size(); ++index) {
3816  if (m_Args[index]->GetDataType() != type)
3817  return false;
3818  }
3819  return true;
3820 }
3821 
3822 
3823 ///////////////////////////////////////////////////////////////////////////////
3824 // class CMacroFunction_ParseRNARelQual
3825 /// ParseRnaRelQual('rna'/'gene', src_field, 'gene'/'rna', dest_field, capitalization, existing_text_opt, delimiter)
3826 /// The last parameter is optional
3827 /// Use this function when you need to convert from/to an RNA qualifier and a Gene qualifier
3828 /// Don't use this function to convert between two RNA qualifiers
3831 {
3832  // The iterator should be an RNA feature
3833  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
3834  const CSeq_feat* rna_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
3835  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
3836  if (!rna_feat || !scope)
3837  return;
3838 
3839  if (rna_feat->IsSetData() && !rna_feat->GetData().IsRna())
3840  return;
3841 
3842  const string& src_feat = m_Args[0]->GetString();
3843  const string& dest_feat = m_Args[2]->GetString();
3844  if (src_feat == "rna" && src_feat == dest_feat)
3845  return;
3846 
3847  if ((src_feat != "rna" && src_feat != "gene") || (dest_feat != "rna" && dest_feat != "gene"))
3848  return;
3849 
3850  size_t index = 4;
3851  const string& capitalization = m_Args[index]->GetString();
3852  const string& action_type = m_Args[++index]->GetString();
3853  string delimiter = (++index < m_Args.size()) ? m_Args[index]->GetString() : kEmptyStr;
3856 
3857  if (src_feat == "rna" && dest_feat == "gene") {
3858  CObjectInfo oi = m_DataIter->GetEditedObject();
3859  CMQueryNodeValue::TObs src_objs;
3860  if (!x_GetSourceFields(oi, 1, src_objs))
3861  return;
3862 
3863  const string dest_field = m_Args[3]->GetString();
3864  // the destination field can be set at this point
3866  CMQueryNodeValue::TObs dest_objs;
3867  bool changed = false, created = false;
3868  CRef<CSeq_feat> dest_feat;
3869  CSeq_feat_Handle fh;
3870  if (!feat_list.empty() && feat_list.size() == 1) {
3871  dest_feat.Reset(new CSeq_feat);
3872  dest_feat->Assign(*feat_list.front());
3873  if (!SetFeatDestinationField(dest_feat, dest_field, dest_objs)) {
3874  return;
3875  }
3876  fh = scope->GetSeq_featHandle(*feat_list.front());
3877  changed = true;
3878  }
3879  else {
3880  // new feature
3881  dest_feat = CreateNewRelatedFeature(*rna_feat, dest_field, *scope);
3882  if (!dest_feat) return;
3883  if (!SetFeatDestinationField(dest_feat, dest_field, dest_objs)) {
3884  return;
3885  }
3886  created = true;
3887  }
3888 
3889  ChangeFields(src_objs, dest_objs);
3890 
3891  if (m_QualsChangedCount) {
3893  if (changed && fh) {
3894  cmd.Reset(new CCmdComposite("Change Related feature"));
3895  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *dest_feat)));
3896  }
3897  else if (created) {
3898  cmd.Reset(new CCmdComposite("Create feature"));
3899  CBioseq_Handle bsh = scope->GetBioseqHandle(dest_feat->GetLocation());
3900  cmd->AddCommand(*CRef<CCmdCreateFeatBioseq>(new CCmdCreateFeatBioseq(bsh, *dest_feat)));
3901  }
3902 
3903  m_DataIter->RunCommand(cmd, m_CmdComposite);
3905  log << m_DataIter->GetBestDescr() << ": parsed " << m_QualsChangedCount << " qualifiers";
3906  x_LogFunction(log);
3907  }
3908  }
3909  else if (src_feat == "gene" && dest_feat == "gene") {
3911  CMQueryNodeValue::TObs src_objs, dest_objs;
3912 
3913  CRef<CSeq_feat> gene_feat;
3914  CSeq_feat_Handle fh;
3915  if (!feat_list.empty() && feat_list.size() == 1) {
3916  gene_feat.Reset(new CSeq_feat);
3917  gene_feat->Assign(*feat_list.front());
3918 
3919  CObjectInfo gene_oi(gene_feat.GetPointer(), gene_feat->GetThisTypeInfo());
3920  if (!x_GetSourceFields(gene_oi, 1, src_objs))
3921  return;
3922 
3923  if (!x_GetDestFields(gene_oi, 3, dest_objs))
3924  return;
3925 
3926  fh = scope->GetSeq_featHandle(*feat_list.front());
3927  }
3928  else {
3929  // no gene was found
3930  return;
3931  }
3932 
3933  ChangeFields(src_objs, dest_objs);
3934 
3935  if (m_QualsChangedCount) {
3937  if (fh) {
3938  cmd.Reset(new CCmdComposite("Change Related feature"));
3939  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *gene_feat)));
3940  }
3941 
3942  m_DataIter->RunCommand(cmd, m_CmdComposite);
3944  log << m_DataIter->GetBestDescr() << ": parsed " << m_QualsChangedCount << " qualifiers";
3945  x_LogFunction(log);
3946  }
3947  }
3948  else if (src_feat == "gene" && dest_feat == "rna") {
3950  CMQueryNodeValue::TObs src_objs, dest_objs;
3951  CRef<CSeq_feat> gene_feat;
3952  if (!feat_list.empty() && feat_list.size() == 1) {
3953  gene_feat.Reset(new CSeq_feat);
3954  gene_feat->Assign(*feat_list.front());
3955 
3956  CObjectInfo gene_oi(gene_feat.GetPointer(), gene_feat->GetThisTypeInfo());
3957  if (!x_GetSourceFields(gene_oi, 1, src_objs))
3958  return;
3959  }
3960  else {
3961  // no gene was found
3962  return;
3963  }
3964 
3965  CObjectInfo oi = m_DataIter->GetEditedObject();
3966  if (!x_GetDestFields(oi, 3, dest_objs))
3967  return;
3968 
3970  if (m_Args[3]->IsString() && NStr::EndsWith(m_Args[3]->GetString(), "::product")) {
3971  for (auto&& it : src_objs) {
3972  CMQueryNodeValue::TObs src_prim_objs;
3973  NMacroUtil::GetPrimitiveObjectInfos(src_prim_objs, it);
3974 
3975  CObjectInfo src = src_prim_objs.front().field;
3976  string src_val = x_GetSourceString(src);
3977 
3978  string remainder;
3979  edit_feat->SetData().SetRna().SetRnaProductName(src_val, remainder);
3981  }
3982  }
3983  else {
3984  ChangeFields(src_objs, dest_objs);
3985  }
3986 
3987  if (m_QualsChangedCount) {
3988  m_DataIter->SetModified();
3990  log << m_DataIter->GetBestDescr() << ": parsed " << m_QualsChangedCount << " qualifiers";
3991  x_LogFunction(log);
3992  }
3993  }
3994 }
3995 
3997 {
3998  if (m_Args.size() < 6 || m_Args.size() > 7)
3999  return false;
4000 
4001  if (!m_Args[0]->IsString() || !m_Args[2]->IsString())
4002  return false;
4003 
4004  for (size_t index = 1; index < 4; index += 2) {
4005  if (!(m_Args[index]->IsString() || m_Args[index]->AreObjects() || m_Args[index]->IsRef()))
4006  return false;
4007  }
4008  for (size_t index = 4; index < m_Args.size(); ++index) {
4009  if (!m_Args[index]->IsString())
4010  return false;
4011  }
4012  return true;
4013 }
4014 
4015 
4016 /// class CMacroFunction_AddParsedText
4017 /// AddParsedText(parsed_text, to_field, capitalization, existing_text_opt, delimiter)
4018 /// Deprecated name: AECRParseStringQual
4019 /// when only the "text" portion is copied
4020 /// The capitalization change applies to the parsed text portion
4021 ///
4023 
4025 {
4026  CObjectInfo oi = m_DataIter->GetEditedObject();
4027 
4028  // obtain the wanted text portion
4029  CMQueryNodeValue& parsed_obj = m_Args[0].GetNCObject();
4030  parsed_obj.Dereference();
4031  if (parsed_obj.GetDataType() != CMQueryNodeValue::eString) {
4032  return;
4033  }
4034  string text_portion = parsed_obj.GetString();
4035  if (text_portion.empty()) {
4036  return;
4037  }
4038  size_t index = 1;
4039  // the destination field might be set during this action
4040  CMQueryNodeValue::TObs dest_objs;
4041  CMQueryNodeValue::EType dest_type = m_Args[index]->GetDataType();
4042 
4043  if (dest_type == CMQueryNodeValue::eString) {
4044  const string& dest_field = m_Args[index]->GetString();
4045  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
4046  GetDestinationObjects(obj, oi, dest_field, dest_objs);
4047  }
4048  else if (dest_type == CMQueryNodeValue::eObjects) {
4049  dest_objs = m_Args[index]->GetObjects();
4050  }
4051  else if (dest_type == CMQueryNodeValue::eRef) {
4052  x_GetObjectsFromRef(dest_objs, index);
4053  }
4054 
4055  if (dest_objs.empty()) {
4056  return;
4057  }
4058 
4059  const string& capitalization = m_Args[++index]->GetString();
4060  const string& action_type = m_Args[++index]->GetString();
4061  string delimiter = (++index < m_Args.size()) ? m_Args[index]->GetString() : kEmptyStr;
4062 
4064  ECapChange cap_change = NMacroUtil::ConvertStringtoCapitalOption(capitalization);
4065 
4066  CSeq_entry_Handle seh = m_DataIter->GetSEH();
4067  FixCapitalizationInString(seh, text_portion, cap_change);
4068  x_ParseFields(dest_objs, text_portion, existing_text);
4069 
4070  if (m_QualsChangedCount) {
4071  NMacroUtil::CleanupForTaxnameChange(dest_objs.front(), oi);
4072  m_DataIter->SetModified();
4074  log << m_DataIter->GetBestDescr() << ": parsed " << m_QualsChangedCount << " fields";
4075  x_LogFunction(log);
4076  }
4077 }
4078 
4080  const string& text_portion, edit::EExistingText existing_text)
4081 {
4083  NMacroUtil::GetPrimitiveObjectInfos(objs, dest_objs.front());
4084  if (objs.empty() && dest_objs.front().field.GetTypeFamily() == eTypeFamilyContainer) {
4085  // add new element when the container is empty
4086  CObjectInfo new_oi(dest_objs.front().field.AddNewElement());
4087  objs.push_back(CMQueryNodeValue::SResolvedField(dest_objs.front().field, new_oi));
4088  }
4089  CObjectInfo dest = objs.front().field;
4091 
4093 
4094  string dest_val = dest.GetPrimitiveValueString();
4095  if (edit::AddValueToString(dest_val, text_portion, existing_text)) {
4096  SetQualStringValue(dest, dest_val);
4097  }
4098  }
4099 }
4100 
4101 
4103 {
4104  size_t as = m_Args.size();
4105  if (as != 4 && as != 5) {
4106  return false;
4107  }
4108 
4109  if (m_Args[0]->GetDataType() != CMQueryNodeValue::eRef) {
4110  return false;
4111  }
4112 
4113  CMQueryNodeValue::EType type = m_Args[1]->GetDataType();
4114  bool type_ok = (type == CMQueryNodeValue::eString)
4116  || (type == CMQueryNodeValue::eRef);
4117  if (!type_ok)
4118  return false;
4119 
4120  for (size_t index = 2; index < as; ++index) {
4121  if (m_Args[index]->GetDataType() != CMQueryNodeValue::eString) {
4122  return false;
4123  }
4124  }
4125 
4126  return true;
4127 }
4128 
4129 // class CMacroFunction_AddParsedFeatQual
4130 /// AddParsedTextToFeatureQual(parsed_text, dest_feature_type, dest_feature_field, capitalization, update_mrna, existing_text_opt, delimiter)
4131 /// The last parameter is optional
4132 /// The related mRNA is only updated if the action is successful and the destination feature is protein
4135 {
4136  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
4137  const CSeq_feat* src_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
4138  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
4139  if (!src_feat || !scope)
4140  return;
4141 
4142  CObjectInfo oi = m_DataIter->GetEditedObject();
4143 
4144  // obtain the wanted text portion
4145  CMQueryNodeValue& parsed_obj = m_Args[0].GetNCObject();
4146  parsed_obj.Dereference();
4147  if (parsed_obj.GetDataType() != CMQueryNodeValue::eString) {
4148  return;
4149  }
4150  string text_portion = parsed_obj.GetString();
4151  if (text_portion.empty()) {
4152  return;
4153  }
4154 
4155  const string& dest_field = m_Args[2]->GetString();
4156  if (dest_field.empty())
4157  return;
4158 
4159  // the destination field can be set at this point
4160  CSeqFeatData::ESubtype target_feature = NMacroUtil::GetFeatSubtype(m_Args[1]->GetString());
4161  NMacroUtil::TVecFeatList feat_list = edit::GetRelatedFeatures(*src_feat, target_feature, scope);
4162  CMQueryNodeValue::TObs dest_objs;
4163  bool changed = false, created = false;
4164  CRef<CSeq_feat> dest_feat;
4165  CSeq_feat_Handle fh;
4166 
4167  if (!feat_list.empty() && feat_list.size() == 1) {
4168  dest_feat.Reset(new CSeq_feat);
4169  dest_feat->Assign(*feat_list.front());
4170  if (!SetFeatDestinationField(dest_feat, dest_field, dest_objs)) {
4171  return;
4172  }
4173  fh = scope->GetSeq_featHandle(*feat_list.front());
4174  changed = true;
4175  }
4176  else {
4177  // new feature
4178  dest_feat = CreateNewRelatedFeature(*src_feat, dest_field, *scope);
4179  if (!dest_feat) return;
4180  if (!SetFeatDestinationField(dest_feat, dest_field, dest_objs)) {
4181  return;
4182  }
4183  created = true;
4184  if (src_feat->GetData().IsCdregion() && src_feat->IsSetXref() && dest_feat->GetData().IsProt()) {
4186  NON_CONST_ITERATE(CSeq_feat::TXref, it, edit_feat->SetXref()) {
4187  if ((*it)->IsSetData() && (*it)->GetData().IsProt()) {
4188  dest_feat->SetData().SetProt().Assign((*it)->GetData().GetProt());
4189  edit_feat->SetXref().erase(it);
4190  break;
4191  }
4192  }
4193  if (edit_feat->GetXref().empty()) {
4194  edit_feat->ResetXref();
4195  }
4196  }
4197  }
4198 
4199  size_t index = 3;
4200  const string& capitalization = m_Args[index]->GetString();
4201  bool update_mrna = m_Args[++index]->GetBool();
4202  const string& action_type = m_Args[++index]->GetString();
4203  string delimiter = (++index < m_Args.size()) ? m_Args[index]->GetString() : kEmptyStr;
4204 
4206  ECapChange cap_change = NMacroUtil::ConvertStringtoCapitalOption(capitalization);
4207 
4208  CSeq_entry_Handle seh = m_DataIter->GetSEH();
4209  FixCapitalizationInString(seh, text_portion, cap_change);
4210  if (IstRNAProductField(*dest_feat, dest_field)) {
4211  string remainder;
4212  dest_feat->SetData().SetRna().SetRnaProductName(text_portion, remainder);
4214  }
4215  else {
4216  x_ParseFields(dest_objs, text_portion, existing_text);
4217  }
4218 
4219  if (m_QualsChangedCount) {
4220  m_DataIter->SetModified();
4222  log << m_DataIter->GetBestDescr() << ": parsed " << m_QualsChangedCount << " fields";
4223 
4224  if (changed && fh) {
4225  CRef<CCmdComposite> cmd(new CCmdComposite("Change Related feature"));
4226  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *dest_feat)));
4227  m_DataIter->RunCommand(cmd, m_CmdComposite);
4228  }
4229  else if (created) {
4230  CRef<CCmdComposite> cmd(new CCmdComposite("Create feature"));
4231  CBioseq_Handle bsh = scope->GetBioseqHandle(dest_feat->GetLocation());
4232  cmd->AddCommand(*CRef<CCmdCreateFeatBioseq>(new CCmdCreateFeatBioseq(bsh, *dest_feat)));
4233  m_DataIter->RunCommand(cmd, m_CmdComposite);
4234  }
4235 
4236  if (update_mrna && dest_feat->GetData().GetSubtype() == CSeqFeatData::eSubtype_prot) {
4237  string message;
4238  CRef<CCmdComposite> cmd = UpdatemRNAProduct(*dest_feat, *scope, message);
4239  if (cmd) {
4240  m_DataIter->RunCommand(cmd, m_CmdComposite);
4241  log << ", " << message;
4242  }
4243  }
4244  x_LogFunction(log);
4245  }
4246 }
4247 
4249 {
4250  if (m_Args.size() < 6 || m_Args.size() > 7)
4251  return false;
4252 
4253  if (m_Args[0]->GetDataType() != CMQueryNodeValue::eRef) {
4254  return false;
4255  }
4257  for (size_t index = 1; index < m_Args.size(); ++index) {
4259  if (m_Args[index]->GetDataType() != type)
4260  return false;
4261  }
4262  return true;
4263 
4264 }
4265 
4266 ///////////////////////////////////////////////////////////////////////////////
4267 // class CMacroFunction_ParseToStructComm
4268 /// ParseToStructComment(text/src_field, structcomm_field ("fieldvalue"|"dbname"|"fieldname"), [fieldname,]
4269 /// capitalization, existing_text_opt, delimiter))
4270 ///
4272 
4274 {
4275  CConstRef<CObject> object = m_DataIter->GetScopedObject().object;
4276  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
4277  if (!scope || !object)
4278  return;
4279 
4280  CObjectInfo oi = m_DataIter->GetEditedObject();
4281  size_t index = 0;
4282 
4283  CMQueryNodeValue text_holder;
4284  string text_portion;
4285 
4286  CMQueryNodeValue::TObs res_oi;
4287  CMQueryNodeValue::EType type = m_Args[index]->GetDataType();
4289  const string& field = m_Args[0]->GetString();
4290  ResolveIdentToSimple(oi, field, text_holder);
4291  GetFieldsByName(&res_oi, oi, field);
4292  }
4293  else if (type == CMQueryNodeValue::eObjects) {
4294  res_oi = m_Args[index]->GetObjects();
4295  if (!res_oi.empty()) {
4296  ResolveIdentToSimple(res_oi.front().field, kEmptyStr, text_holder);
4297  }
4298  }
4299  else if (type == CMQueryNodeValue::eRef) {
4300  CMQueryNodeValue& objs = m_Args[index].GetNCObject();
4301  objs.Dereference();
4302 
4303  if (objs.GetDataType() == CMQueryNodeValue::eObjects) {
4304  res_oi = objs.GetObjects();
4305  if (!res_oi.empty()) {
4306  ResolveIdentToSimple(res_oi.front().field, kEmptyStr, text_holder);
4307  }
4308  }
4309  else if (objs.GetDataType() == CMQueryNodeValue::eString) {
4310  text_portion = objs.GetString();
4311  }
4312  }
4313 
4314  if (text_holder.GetDataType() == CMQueryNodeValue::eString && text_portion.empty()) {
4315  text_portion = text_holder.GetString();
4316  }
4317 
4318  if (text_portion.empty())
4319  return;
4320 
4321  x_SetFieldType(m_Args[++index]->GetString());
4322  string fieldname = (m_Type == eFieldValue) ? m_Args[++index]->GetString() : kEmptyStr;
4323  if (m_Type == eFieldError) {
4324  NCBI_THROW(CMacroExecException, eWrongArguments, "Wrong structured comment fieldname is given (consider replacing it with either 'fieldvalue', 'dbname' or 'fieldname'");
4325  }
4326 
4327  string capitalization, action_type;
4328  if (++index < m_Args.size()) {
4329  capitalization = m_Args[index]->GetString();
4330  }
4331  if (++index < m_Args.size()) {
4332  action_type = m_Args[index]->GetString();
4333  }
4334  if (capitalization.empty() || action_type.empty()) {
4335  NCBI_THROW(CMacroExecException, eWrongArguments, "Wrong arguments specified");
4336  }
4337 
4338  string delimiter = (++index < m_Args.size()) ? m_Args[index]->GetString() : kEmptyStr;
4339 
4340  ECapChange cap_change = NMacroUtil::ConvertStringtoCapitalOption(capitalization);
4341  CSeq_entry_Handle seh = m_DataIter->GetSEH();
4342  FixCapitalizationInString(seh, text_portion, cap_change);
4343 
4345  CBioseq_Handle bsh = m_DataIter->GetBioseqHandle();
4346  if (!bsh)
4347  return;
4348 
4350  CSeqdesc_CI strcomm_it(bsh, CSeqdesc::e_User);
4351  // obtain the existing structured comment
4352  for ( ; strcomm_it; ++strcomm_it) {
4353  if (CComment_rule::IsStructuredComment(strcomm_it->GetUser())) {
4354  break;
4355  }
4356  }
4357  const string kPrefix = "StructuredCommentPrefix";
4358  const string kSuffix = "StructuredCommentSuffix";
4359 
4360  if (strcomm_it) {
4361  CRef<CSeqdesc> new_desc(new CSeqdesc);
4362  new_desc->Assign(*strcomm_it);
4363 
4364  CUser_object& user_object = new_desc->SetUser();
4365  if (existing_text == edit::eExistingText_add_qual) {
4366  // add a new field to the structured comment
4367  if (m_Type == eFieldValue) {
4368  user_object.AddField(fieldname, text_portion);
4369  m_QualsChangedCount++;
4370  }
4371  }
4372  else {
4373  if (m_Type == eFieldValue) {
4374  if (user_object.HasField(fieldname)) {
4375  CUser_field& user_field = user_object.SetField(fieldname);
4376  if (user_field.IsSetData() && user_field.GetData().IsStr()) {
4377  string orig_val = user_field.GetData().GetStr();
4378  if (AddValueToString(orig_val, text_portion, existing_text)) {
4379  user_field.SetData().SetStr(orig_val);
4380  m_QualsChangedCount++;
4381  }
4382  }
4383  }
4384  else {
4385  // add a new field to the structured comment
4386  user_object.AddField(fieldname, text_portion);
4387  m_QualsChangedCount++;
4388  }
4389  }
4390  else if (m_Type == eDbName) {
4391  m_QualsChangedCount += CMacroFunction_SetStructCommDb::s_UpdateStructCommentDb(*new_desc, kPrefix, text_portion, existing_text);
4392  m_QualsChangedCount += CMacroFunction_SetStructCommDb::s_UpdateStructCommentDb(*new_desc, kSuffix, text_portion, existing_text);
4393  }
4394  else if (m_Type == eFieldName) {
4395  EDIT_EACH_USERFIELD_ON_USEROBJECT(field_it, user_object) {
4396  CUser_field& user_field = **field_it;
4397  if (user_field.GetLabel().IsStr() &&
4398  !NStr::Equal(user_field.GetLabel().GetStr(), kPrefix) &&
4399  !NStr::Equal(user_field.GetLabel().GetStr(), kSuffix)) {
4400  string orig_val = user_field.GetLabel().GetStr();
4401  if (AddValueToString(orig_val, text_portion, existing_text)) {
4402  user_field.SetLabel().SetStr(orig_val);
4403  m_QualsChangedCount++;
4404  }
4405  }
4406  }
4407  }
4408 
4409  if (m_QualsChangedCount) {
4411  CCleanup::CleanupUserObject(new_desc->SetUser());
4412 
4413  CRef<CCmdChangeSeqdesc> ecmd(new CCmdChangeSeqdesc(strcomm_it.GetSeq_entry_Handle(), *strcomm_it, *new_desc));
4414  cmd.Reset(new CCmdComposite("Update structured comment"));
4415  cmd->AddCommand(*ecmd);
4416  }
4417  }
4418 
4419  }
4420  else { // make a new one
4421  if ( existing_text == edit::eExistingText_leave_old) {
4422  return;
4423  }
4424 
4426  CRef<CSeqdesc> new_desc(new CSeqdesc());
4427  CUser_object& user_object = new_desc->SetUser();
4429  switch (m_Type) {
4430  case eFieldValue:
4431  user_object.AddField(fieldname, text_portion);
4432  m_QualsChangedCount++;
4433  break;
4434  case eDbName:
4435  user_object.AddField(kPrefix, CComment_rule::MakePrefixFromRoot(text_portion));
4436  user_object.AddField(kSuffix, CComment_rule::MakeSuffixFromRoot(text_portion));
4437  m_QualsChangedCount++;
4438  break;
4439  case eFieldName:
4440  user_object.AddField(text_portion, kEmptyStr);
4441  m_QualsChangedCount++;
4442  break;
4443  default:
4444  break;
4445  }
4446 
4447  if (m_QualsChangedCount) {
4448  cmd.Reset(new CCmdComposite("Create structured comment"));
4449  cmd->AddCommand(*(new CCmdCreateDesc(bsh.GetSeq_entry_Handle(), *new_desc)));
4450  }
4451  }
4452 
4453  if (cmd) {
4454  m_DataIter->RunCommand(cmd, m_CmdComposite);
4455 
4456  TChangedQuals report;
4457  string msg = "parsing text to structured comment ";
4458  switch (m_Type) {
4459  case eFieldValue:
4460  msg += "field '" + fieldname + "'";
4461  break;
4462  case eDbName:
4463  msg += "database name";
4464  break;
4465  case eFieldName:
4466  msg += "fieldname";
4467  break;
4468  default:
4469  break;
4470  }
4471  report[msg] = m_QualsChangedCount;
4472  CRef<IFunctionLog> fnc_log(new CGeneralFuncLog(report));
4473  x_LogChangedQuals(fnc_log);
4474  }
4475 }
4476 
4478 {
4479  if (m_Args.size() > 6 || m_Args.size() < 4) {
4480  return false;
4481  }
4482  if (!(m_Args[0]->IsString() || m_Args[0]->AreObjects() || m_Args[0]->IsRef()))
4483  return false;
4484 
4485  for (size_t index = 1; index < m_Args.size(); ++index) {
4486  if (m_Args[index]->GetDataType() != CMQueryNodeValue::eString)
4487  return false;
4488  }
4489  return true;
4490 }
4491 
4492 void CMacroFunction_ParseToStructComm::x_SetFieldType(const string& strcomm_field)
4493 {
4494  m_Type = eFieldError;
4495  if (NStr::EqualNocase(strcomm_field, kStrCommFieldValue)) {
4496  m_Type = eFieldValue;
4497  }
4498  else if (NStr::EqualNocase(strcomm_field, kStrCommDbname)) {
4499  m_Type = eDbName;
4500  }
4501  else if (NStr::EqualNocase(strcomm_field, kStrCommFieldName)) {
4502  m_Type = eFieldName;
4503  }
4504 }
4505 
4506 
4507 ///////////////////////////////////////////////////////////////////////////////
4508 /// class CMacroFunction_ParsedText
4509 /// Obtains a portion of the text
4510 /// ParsedText(field_name(str/objects), left_del(str), include_left(b), right_del(str), include_right(b),
4511 /// case_sensitive(b), whole_word(b), rmv_from_parsed(b), rmv_left(b), rmv_right(b));
4512 /// left_del and right_del can be free_text, "eDigits", "eLetters"
4513 /// the last three parameters are optional
4514 /// It may also modify the content of the field
4515 ///
4518 {
4519  m_ChangedDescriptors.clear();
4520  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
4521  CObjectInfo oi = m_DataIter->GetEditedObject();
4522 
4523  CMQueryNodeValue::TObs res_oi;
4524  CMQueryNodeValue::EType type = m_Args[0]->GetDataType();
4526  const string& field = m_Args[0]->GetString();
4527  if (NStr::EqualNocase(field, "localid") || NStr::EqualNocase(field, "defline")) {
4528  x_GetSpecialField(field, res_oi, *scope);
4529  }
4530  else {
4531  ResolveIdentToSimple(oi, field, *m_Result);
4532  GetFieldsByName(&res_oi, oi, field);
4533  }
4534  }
4535  else {
4537  res_oi = m_Args[0]->GetObjects();
4538  }
4539  else if (type == CMQueryNodeValue::eRef) {
4540  x_GetObjectsFromRef(res_oi, 0);
4542  }
4543 
4544  if (res_oi.empty()) return;
4545  ResolveIdentToSimple(res_oi.front().field, kEmptyStr, *m_Result);
4546  }
4547 
4550  return;
4551  }
4552 
4553  const string& full_text = m_Result->GetString();
4555  string parsed_text = options->GetSelectedText(full_text);
4556  m_Result->SetString(parsed_text);
4557 
4558  if (options->ShouldRemoveFromParsed()) {
4559  if (!m_ChangedDescriptors.empty()) {
4560  auto it = m_ChangedDescriptors.begin();
4561  if (CSeqdesc* desc = dynamic_cast<CSeqdesc*>(it->second.GetNCPointer())) {
4562  if (desc->IsTitle()) {
4563  string orig_val = desc->GetTitle();
4564  options->RemoveSelectedText(orig_val);
4565  if (!orig_val.empty()) {
4566  desc->SetTitle() = orig_val;
4567 
4568  CRef<CCmdChangeSeqdesc> chg_cmd(new CCmdChangeSeqdesc(it->first.GetSeq_entry_Handle(), *it->first, *it->second));
4569  CRef<CCmdComposite> cmd(new CCmdComposite("Update definition line"));
4570  cmd->AddCommand(*chg_cmd);
4571  m_DataIter->RunCommand(cmd, m_CmdComposite);
4572  }
4573  // the title will not be deleted
4574  }
4575  }
4576  }
4577  else if (!res_oi.empty()) {
4579  NMacroUtil::GetPrimitiveObjectInfos(objs, res_oi.front());
4580  CObjectInfo objInfo = objs.front().field;
4582 
4583  bool is_taxname = NMacroUtil::IsTaxname(objs.front());
4584  string orig_val = objInfo.GetPrimitiveValueString();
4585  options->RemoveSelectedText(orig_val);
4586  if (orig_val.empty()) {
4587  RemoveFieldByName(res_oi.front());
4589  }
4590  else {
4591  SetQualStringValue(objInfo, orig_val);
4592  }
4593  if (is_taxname) {
4595  }
4596  }
4597  }
4598 
4599  if (m_QualsChangedCount) {
4600  m_DataIter->SetModified();
4601  }
4602 }
4603 
4605 {
4606  size_t as = m_Args.size();
4607  if (as < 7 || as > 10) {
4608  return false;
4609  }
4610  if (!(m_Args[0]->IsString() || m_Args[0]->AreObjects() || m_Args[0]->IsRef()))
4611  return false;
4612 
4613  if (!m_Args[1]->IsString() || !m_Args[2]->IsBool() || !m_Args[3]->IsString()) {
4614  return false;
4615  }
4616 
4617  for (size_t i = 4; i < as; ++i) {
4618  if (!m_Args[i]->IsBool())
4619  return false;
4620  }
4621  return true;
4622 }
4623 
4625 {
4626  CBioseq_Handle bsh = m_DataIter->GetBioseqHandle();
4627  if (bsh && bsh.IsAa()) {
4628  const CSeq_feat* cds = sequence::GetCDSForProduct(*bsh.GetCompleteBioseq(), &scope);
4629  if (cds) {
4630  bsh = scope.GetBioseqHandle(cds->GetLocation());
4631  }
4632  }
4633  if (!bsh) return false;
4634 
4635  if (NStr::EqualNocase(field, "defline")) {
4636  CSeqdesc_CI title_ci(bsh, CSeqdesc::e_Title, 1);
4637  if (title_ci && !title_ci->GetTitle().empty()) {
4638  CRef<CSeqdesc> new_desc(new CSeqdesc);
4639  new_desc->Assign(*title_ci);
4640  CObjectInfo oi(new_desc, new_desc->GetThisTypeInfo());
4641  CObjectInfo parent;
4642  objs.push_back(CMQueryNodeValue::SResolvedField(parent, oi));
4643  if (ResolveIdentToSimple(oi, "title", *m_Result)) {
4644  m_ChangedDescriptors.emplace_back(title_ci, new_desc);
4645  return true;
4646  }
4647  }
4648  }
4649  else if (NStr::EqualNocase(field, "localid")) {
4650  for (CSeqdesc_CI desc(bsh, CSeqdesc::e_User); desc; ++desc) {
4651  const CUser_object& user = desc->GetUser();
4653  if (!user.GetData().empty()) {
4654  const CRef<CUser_field>& user_field = user.GetData().front();
4655  if (user_field->IsSetLabel() && user_field->GetLabel().IsStr()
4656  && user_field->IsSetData()
4657  && NStr::EqualCase(user_field->GetLabel().GetStr(), "LocalId")) {
4658 
4659  if (user_field->GetData().IsStr()) {
4660  CObjectInfo objInfo(user_field.GetNCPointer(), user_field->GetTypeInfo());
4661  if (ResolveIdentToSimple(objInfo, "data.str", *m_Result))
4662  return true;
4663  }
4664  }
4665  }
4666  }
4667  }
4668 
4669 
4671  CBioseq& seq = const_cast<CBioseq&>(bsh.GetCompleteBioseq().GetObject());
4672  CObjectInfo objInfo(&seq, seq.GetTypeInfo());
4673  if (ResolveIdentToSimple(objInfo, "id.local.str", *m_Result)) {
4674  return true;
4675  }
4676  }
4677  }
4678  return false;
4679 }
4680 
4682 {
4683  CRef<edit::CParseTextOptions> options(new edit::CParseTextOptions());
4684  const string& left_del = m_Args[start_index]->GetString();
4685  if (NStr::EqualCase(left_del, "eDigits")) {
4686  options->SetStartDigits();
4687  }
4688  else if (NStr::EqualCase(left_del, "eLetters")) {
4689  options->SetStartLetters();
4690  }
4691  else {
4692  options->SetStartText(left_del);
4693  }
4694  options->SetIncludeStart(m_Args[++start_index]->GetBool()); // include_start
4695 
4696  const string& right_del = m_Args[++start_index]->GetString();
4697  if (NStr::EqualCase(right_del, "eDigits")) {
4698  options->SetStopDigits();
4699  }
4700  else if (NStr::EqualCase(right_del, "eLetters")) {
4701  options->SetStopLetters();
4702  }
4703  else {
4704  options->SetStopText(right_del);
4705  }
4706  options->SetIncludeStop(m_Args[++start_index]->GetBool()); // include_stop
4707 
4708  options->SetCaseInsensitive(!m_Args[++start_index]->GetBool()); // case_sensitivity
4709  options->SetWholeWord(m_Args[++start_index]->GetBool());
4710 
4711  auto nr_args = m_Args.size();
4712  if (++start_index < nr_args) {
4713  options->SetShouldRemove(m_Args[start_index]->GetBool());
4714  }
4715  if (++start_index < nr_args) {
4716  options->SetShouldRmvBeforePattern(m_Args[start_index]->GetBool());
4717  }
4718  if (++start_index < nr_args) {
4719  options->SetShouldRmvAfterPattern(m_Args[start_index]->GetBool());
4720  }
4721 
4722  return options;
4723 }
4724 
4725 
4726 // class CMacroFunction_ParsedTextFrom
4727 /// Obtains a portion of the text from a different feature that the current one
4728 /// ParsedTextFromFeature(feature_type, field_name(str/objects), left_del(str), include_left(b), right_del(str), include_right(b),
4729 /// case_sensitive(b), whole_word(b), rmv_from_parsed(b), rmv_left(b), rmv_right(b));
4730 /// left_del and right_del can be free_text, "eDigits", "eLetters"
4731 /// the last three parameters are optional
4732 /// It may also modify the content of the field
4733 ///
4736 {
4737  // The iterator should be an RNA feature - TODO: extend it to accept other features as well
4738  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
4739  const CSeq_feat* rna_feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
4740  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
4741  if (!rna_feat || !scope)
4742  return;
4743 
4744  if (rna_feat->IsSetData() && !rna_feat->GetData().IsRna())
4745  return;
4746 
4747  const string& src_feat = m_Args[0]->GetString();
4748  if (src_feat != "gene")
4749  return;
4750 
4752  CMQueryNodeValue::TObs res_oi;
4753  CRef<CSeq_feat> gene_feat;
4754  CSeq_feat_Handle fh;
4755  if (!feat_list.empty() && feat_list.size() == 1) {
4756  gene_feat.Reset(new CSeq_feat);
4757  gene_feat->Assign(*feat_list.front());
4758 
4759  CObjectInfo gene_oi(gene_feat.GetPointer(), gene_feat->GetThisTypeInfo());
4760  size_t index = 1;
4761  if (m_Args[index]->IsString()) {
4762  if (!GetFieldsByName(&res_oi, gene_oi, m_Args[index]->GetString()))
4763  return;
4764  }
4765  else if (m_Args[index]->AreObjects()) {
4766  res_oi = m_Args[index]->GetObjects();
4767  }
4768  else if (m_Args[index]->IsRef()) {
4769  x_GetObjectsFromRef(res_oi, index);
4771  }
4772 
4773  fh = scope->GetSeq_featHandle(*feat_list.front());
4774  }
4775 
4776 
4777  if (res_oi.empty())
4778  return;
4779 
4780  ResolveIdentToSimple(res_oi.front().field, kEmptyStr, *m_Result);
4781  if (!m_Result->IsString()) {
4783  return;
4784  }
4785 
4786  const string& full_text = m_Result->GetString();
4788  string parsed_text = options->GetSelectedText(full_text);
4789  m_Result->SetString(parsed_text);
4790 
4791  if (!parsed_text.empty() && options->ShouldRemoveFromParsed()) {
4793  NMacroUtil::GetPrimitiveObjectInfos(objs, res_oi.front());
4794  CObjectInfo objInfo = objs.front().field;
4796 
4797 
4798  string orig_val = objInfo.GetPrimitiveValueString();
4799  options->RemoveSelectedText(orig_val);
4800  if (orig_val.empty()) {
4801  RemoveFieldByName(res_oi.front());
4803  }
4804  else {
4805  SetQualStringValue(objInfo, orig_val);
4806  }
4807 
4809  if (fh) {
4810  cmd.Reset(new CCmdComposite("Remove parsed text from gene"));
4811  cmd->AddCommand(*CRef<CCmdChangeSeq_feat>(new CCmdChangeSeq_feat(fh, *gene_feat)));
4812  m_DataIter->RunCommand(cmd, m_CmdComposite);
4813  }
4814  }
4815 }
4816 
4818 {
4819  size_t as = m_Args.size();
4820  if (as < 8 || as > 11) {
4821  return false;
4822  }
4823  if (!m_Args[0]->IsString() || (!(m_Args[1]->IsString() || m_Args[1]->AreObjects() || m_Args[1]->IsRef())))
4824  return false;
4825 
4826  if (!m_Args[2]->IsString() || !m_Args[3]->IsBool() || !m_Args[4]->IsString()) {
4827  return false;
4828  }
4829 
4830  for (size_t i = 5; i < as; ++i) {
4831  if (!m_Args[i]->IsBool())
4832  return false;
4833  }
4834  return true;
4835 }
4836 
4837 ///////////////////////////////////////////////////////////////////////////////
4838 /// class CMacroFunction_LocalID
4839 /// Resolves the local id: the original id if there is one, otherwise the actual local id on the sequence
4840 ///
4841 DEFINE_MACRO_FUNCNAME(CMacroFunction_LocalID, "LocalID")
4842 void CMacroFunction_LocalID::TheFunction()
4843 {
4844  CBioseq_Handle bsh = m_DataIter->GetBioseqHandle();
4845  if (!bsh) return;
4846 
4847  for (CSeqdesc_CI desc(bsh, CSeqdesc::e_User); desc; ++desc) {
4848  const CUser_object& user = desc->GetUser();
4850  if (!user.GetData().empty()) {
4851  const CRef<CUser_field>& user_field = user.GetData().front();
4852  if (user_field->IsSetLabel() && user_field->GetLabel().IsStr()
4853  && user_field->IsSetData()
4854  && NStr::EqualCase(user_field->GetLabel().GetStr(), "LocalId")) {
4855 
4856  if (user_field->GetData().IsStr()) {
4857  CObjectInfo objInfo(user_field.GetNCPointer(), user_field->GetTypeInfo());
4858  if (ResolveIdentToObjects(objInfo, "data.str", *m_Result))
4859  return;
4860  }
4861  }
4862  }
4863  }
4864  }
4865 
4866 
4867  if (m_Result->IsNotSet()) {
4868  CBioseq& seq = const_cast<CBioseq&>(bsh.GetCompleteBioseq().GetObject());
4869  CObjectInfo objInfo(&seq, seq.GetTypeInfo());
4870  ResolveIdentToObjects(objInfo, "id.local.str", *m_Result);
4871  if (m_Result->IsNotSet()) {
4872  ResolveIdentToObjects(objInfo, "id.local.id", *m_Result);
4873  }
4874  }
4875 
4876 }
4877 
4878 bool CMacroFunction_LocalID::x_ValidArguments() const
4879 {
4880  return (m_Args.empty());
4881 }
4882 
4883 
4884 ///////////////////////////////////////////////////////////////////////////////
4885 /// class CMacroFunction_SetQual
4886 /// SetQual(field_name, newValue)
4887 ///
4889 
4890 void CMacroFunction_SetQual::TheFunction()
4891 {
4892  CMQueryNodeValue::EType type = m_Args[0]->GetDataType();
4893  CMQueryNodeValue& new_value = *m_Args[1];
4894 
4895  CObjectInfo oi = m_DataIter->GetEditedObject();
4896  CMQueryNodeValue::TObs res_oi;
4898  if (!SetFieldsByName(&res_oi, oi, m_Args[0]->GetString())) {
4899  return;
4900  }
4901  }
4902  else if (type == CMQueryNodeValue::eObjects) {
4903  res_oi = m_Args[0]->GetObjects();
4904  }
4905  else if (type == CMQueryNodeValue::eRef) {
4906  x_GetObjectsFromRef(res_oi, 0);
4907  }
4908 
4909  if (res_oi.empty()) {
4910  return;
4911  }
4912 
4914  if (SetSimpleTypeValue(it->field, new_value)) {
4915  m_QualsChangedCount++;
4916  }
4917  }
4918 
4919  if (m_QualsChangedCount) {
4920  NMacroUtil::CleanupForTaxnameChange(res_oi.front(), oi);
4921  m_DataIter->SetModified();
4923  log << m_DataIter->GetBestDescr() << ": set new value to " << m_QualsChangedCount << " qualifiers";
4924  x_LogFunction(log);
4925  }
4926 }
4927 
4929 {
4930  // can accept as its first parameter: objects, string or reference
4931  CMQueryNodeValue::EType type = m_Args[0]->GetDataType();
4933  if (m_Args.size() != 2 || !first_ok)
4934  return false;
4935 
4936  if (!m_Args[1]->IsSimpleType()) {
4937  return false;
4938  }
4939  return true;
4940 }
4941 
4942 
4943 ///////////////////////////////////////////////////////////////////////////////
4944 // class CMacroFunction_AddDBLink
4945 /// AddDBLink(dblink_type, newValue, existing_text, delimiter, remove_blank)
4946 /// The last parameter is optional
4947 ///
4949 
4950 static void s_AddNewDBlinkValue(CUser_field& user_field, const string& newValue);
4951 
4952 static void s_SetVectorValue(CUser_field& user_field, const string& newValue, const string& del);
4953 
4954 static bool s_AddNewUserField(CRef<CSeqdesc>& user_object_desc, const string& dblink, const string& newValue);
4955 
4956 void CMacroFunction_AddDBLink::TheFunction()
4957 {
4958  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
4959  const CBioseq* bseq = dynamic_cast<const CBioseq*>(obj.GetPointer());
4960  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
4961  if (!scope || !bseq || bseq->IsAa())
4962  return;
4963 
4964  size_t index = 0;
4965  const string& dblink = m_Args[index]->GetString();
4966  string newValue = NMacroUtil::GetStringValue(m_Args[++index]);
4967  const string& existing_text_option = m_Args[++index]->GetString();
4968  string delimiter;
4969  bool remove_field = false;
4970  x_GetOptionalArgs(delimiter, remove_field, index);
4971  edit::EExistingText existing_text = NMacroUtil::ActionTypeToExistingTextOption(existing_text_option, delimiter);
4972 
4974 
4975  if (!newValue.empty()) {
4976  vector<pair<CSeqdesc_CI, CRef<CSeqdesc>>> changed_descs;
4977  CBioseq_Handle bsh = m_DataIter->GetBioseqHandle();
4978  if (!bsh)
4979  return;
4980 
4981  for (CSeqdesc_CI desc_it(bsh, CSeqdesc::e_User); desc_it; ++desc_it) {
4982  if (desc_it->GetUser().GetType().IsStr() && desc_it->GetUser().GetType().GetStr() == "DBLink") {
4983  CRef<CSeqdesc> new_desc(new CSeqdesc);
4984  new_desc->Assign(*desc_it);
4985 
4986  bool found_user_field = false;
4987  EDIT_EACH_USERFIELD_ON_USEROBJECT(user_it, new_desc->SetUser()) {
4988  CUser_field& field = **user_it;
4989  if (field.GetLabel().IsStr() && NStr::Equal(field.GetLabel().GetStr(), dblink) && field.IsSetData()) {
4990  found_user_field = true;
4991  if (field.GetData().IsStrs()) {
4992  if (existing_text == edit::eExistingText_add_qual) {
4993  s_AddNewDBlinkValue(field, newValue);
4994  m_QualsChangedCount++;
4995  }
4996  else if (existing_text == edit::eExistingText_replace_old) {
4997  // apply the same logic as in SetStrinQual:
4998  // keep the first element, update it and delete the rest
4999  field.SetData().Reset();
5000  field.ResetNum();
5001  s_AddNewDBlinkValue(field, newValue);
5002  m_QualsChangedCount++;
5003 
5004  } else {
5005  // update all of them
5006  for (auto& it : field.SetData().SetStrs()) {
5007  string orig_value = it;
5008  if (edit::AddValueToString(orig_value, newValue, existing_text)) {
5009  it = orig_value;
5010  m_QualsChangedCount++;
5011  }
5012  }
5013  }
5014  }
5015  }
5016  }
5017 
5018  if (!found_user_field && s_AddNewUserField(new_desc, dblink, newValue)) {
5019  m_QualsChangedCount++;
5020  }
5021  changed_descs.push_back(make_pair(desc_it, new_desc));
5022  }
5023  }
5024 
5025  if (changed_descs.empty()) {
5026  CRef<CSeqdesc> new_desc(new CSeqdesc);
5027  new_desc->SetUser().SetType().SetStr("DBLink");
5028  if (s_AddNewUserField(new_desc, dblink, newValue))
5029  m_QualsChangedCount++;
5030 
5031  cmd.Reset(new CCmdComposite("Create DBLink user object"));
5032  cmd->AddCommand(*(new CCmdCreateDesc(bsh.GetSeq_entry_Handle(), *new_desc)));
5033  }
5034  else if (!changed_descs.empty()) {
5035  cmd.Reset(new CCmdComposite("Update DBLink user object"));
5036  for (auto& it : changed_descs) {
5037  CRef<CCmdChangeSeqdesc> chg_cmd(new CCmdChangeSeqdesc(it.first.GetSeq_entry_Handle(), *it.first, *it.second));
5038  cmd->AddCommand(*chg_cmd);
5039  }
5040  }
5041 
5042  if (m_QualsChangedCount) {
5043  TChangedQuals report;
5044  report["setting new value to " + dblink] = m_QualsChangedCount;
5045  CRef<IFunctionLog> fnc_log(new CGeneralFuncLog(report));
5046  x_LogChangedQuals(fnc_log);
5047  }
5048  }
5049  else if (remove_field) {
5050  CBioseq_Handle bsh = m_DataIter->GetBioseqHandle();
5051  if (!bsh)
5052  return;
5053 
5054  for (CSeqdesc_CI desc_it(bsh, CSeqdesc::e_User); desc_it; ++desc_it) {
5055  if (desc_it->GetUser().GetType().IsStr() && desc_it->GetUser().GetType().GetStr() == "DBLink") {
5056  CRef<CSeqdesc> new_desc(new CSeqdesc);
5057  new_desc->Assign(*desc_it);
5058 
5059  EDIT_EACH_USERFIELD_ON_USEROBJECT(user_it, new_desc->SetUser()) {
5060  CUser_field& field = **user_it;
5061  if (field.GetLabel().IsStr() && NStr::Equal(field.GetLabel().GetStr(), dblink) && field.IsSetData()) {
5062  ERASE_USERFIELD_ON_USEROBJECT(user_it, new_desc->SetUser());
5063  m_QualsChangedCount++;
5064  }
5065  }
5066  if (new_desc->GetUser().GetData().empty()) {
5067  // to be deleted
5068  if (!cmd) {
5069  cmd.Reset(new CCmdComposite("Delete DBLink user object"));
5070  }
5071  cmd->AddCommand(*(new CCmdDelDesc(desc_it.GetSeq_entry_Handle(), *desc_it)));
5072  }
5073  else {
5074  if (!cmd) {
5075  cmd.Reset(new CCmdComposite("Update DBLink user object"));
5076  }
5077  CRef<CCmdChangeSeqdesc> chg_cmd(new CCmdChangeSeqdesc(desc_it.GetSeq_entry_Handle(), *desc_it, *new_desc));
5078  cmd->AddCommand(*chg_cmd);
5079  }
5080  }
5081  }
5082  if (m_QualsChangedCount) {
5083  TChangedQuals report;
5084  report["removal of " + dblink + " value"] = m_QualsChangedCount;
5085  CRef<IFunctionLog> fnc_log(new CGeneralFuncLog(report));
5086  x_LogChangedQuals(fnc_log);
5087  }
5088  }
5089 
5090  if (m_QualsChangedCount) {
5091  m_DataIter->RunCommand(cmd, m_CmdComposite);
5092  }
5093 }
5094 
5095 bool s_AddNewUserField(CRef<CSeqdesc>& user_object_desc, const string& dblink, const string& newValue)
5096 {
5097  if (!user_object_desc || dblink.empty())
5098  return false;
5099 
5100  CRef<CUser_field> new_field(new CUser_field);
5101  new_field->SetLabel().SetStr(dblink);
5102 
5103  string del = (newValue.find(',') != NPOS) ? "," : kEmptyStr;
5104  if (del.empty() && newValue.find(';') != NPOS) {
5105  del = ";";
5106  }
5107 
5108  if (del.empty()) {
5109  new_field->SetNum(1);
5110  new_field->SetData().SetStrs().push_back(newValue);
5111  }
5112  else {
5113  s_SetVectorValue(*new_field, newValue, del);
5114  }
5115 
5116  if (new_field->IsSetData() && new_field->GetData().IsStrs()) {
5117  new_field->SetNum((int)new_field->GetData().GetStrs().size());
5118  }
5119  user_object_desc->SetUser().SetData().push_back(new_field);
5120  return true;
5121 }
5122 
5123 
5124 void s_SetVectorValue(CUser_field& user_field, const string& newValue, const string& del)
5125 {
5126  vector<string> values;
5127  NStr::Split(newValue, del, values);
5128  for (auto&& it : values)
5130  user_field.SetValue(values);
5131 }
5132 
5133 static string s_GatherExistingValues(CUser_field& user_field, const string& newValue, const string& del)
5134 {
5135  string tmp_values;
5136  if (user_field.IsSetData() && user_field.GetData().IsStrs()) {
5137  for (auto&& it : user_field.GetData().GetStrs()) {
5138  if (!tmp_values.empty()) {
5139  tmp_values += del + " ";
5140  }
5141  tmp_values += it;
5142  }
5143  }
5144  if (!tmp_values.empty()) {
5145  tmp_values += del + " ";
5146  }
5147  tmp_values += newValue;
5148  return tmp_values;
5149 }
5150 
5151 void s_AddNewDBlinkValue(CUser_field& user_field, const string& newValue)
5152 {
5153  string del = (newValue.find(',') != NPOS) ? "," : kEmptyStr;
5154  if (del.empty() && newValue.find(';') != NPOS) {
5155  del = ";";
5156  }
5157 
5158  if (del.empty()) {
5159  user_field.SetData().SetStrs().push_back(newValue);
5160  }
5161  else {
5162  string tmp_values = s_GatherExistingValues(user_field, newValue, del);
5163  s_SetVectorValue(user_field, tmp_values, del);
5164  }
5165  if (user_field.IsSetData() && user_field.GetData().IsStrs()) {
5166  user_field.SetNum((int)user_field.GetData().GetStrs().size());
5167  }
5168 }
5169 
5171 {
5172  auto arg_nr = m_Args.size();
5173  if (arg_nr < 3 || arg_nr > 5) {
5174  return false;
5175  }
5176 
5177  size_t index = 0;
5178  if (!m_Args[index]->IsString()) return false;
5179  NMacroUtil::GetPrimitiveFromRef(m_Args[++index].GetNCObject());
5180  if (!m_Args[index]->IsString() && !m_Args[index]->IsInt())
5181  return false;
5182 
5183  if (!m_Args[++index]->IsString()) return false;
5184  if (arg_nr > 3 && (!m_Args[++index]->IsString() && !m_Args[index]->IsBool())) return false;
5185  if (arg_nr > 4 && !m_Args[++index]->IsBool()) return false;
5186  return true;
5187 }
5188 
5189 ///////////////////////////////////////////////////////////////////////////////
5190 /// class CMacroFunction_AddUnverified
5191 /// AddUnverified("Features");
5192 /// The user object will be added only to nucleotide sequences
5193 DEFINE_MACRO_FUNCNAME(CMacroFunction_AddUnverified, "AddUnverified")
5194 
5196 
5197 void CMacroFunction_AddUnverified::TheFunction()
5198 {
5199  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
5200  const CBioseq* bseq = dynamic_cast<const CBioseq*>(obj.GetPointer());
5201  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
5202  if (!scope || !bseq || bseq->IsAa())
5203  return;
5204 
5207  return;
5208 
5209  vector<pair<CSeqdesc_CI, CRef<CSeqdesc>>> changed_descs;
5210  CBioseq_Handle bsh = m_DataIter->GetBioseqHandle();
5211 
5212  for (CSeqdesc_CI desc_it(bsh, CSeqdesc::e_User); desc_it; ++desc_it) {
5213  if (desc_it->GetUser().IsUnverified()) {
5214  const auto& present_user = desc_it->GetUser();
5215 
5216  // don't add the same type of Unverified user object to the sequence if one already exists
5217  if ((type == NMacroUtil::eUnVer_Features && present_user.IsUnverifiedFeature()) ||
5218  (type == NMacroUtil::eUnVer_Organism && present_user.IsUnverifiedOrganism()) ||
5219  (type == NMacroUtil::eUnVer_Misassembled && present_user.IsUnverifiedMisassembled()) ||
5220  (type == NMacroUtil::eUnVer_Contaminant && present_user.IsUnverifiedContaminant())) {
5221  return;
5222  }
5223 
5224  CRef<CSeqdesc> new_desc(new CSeqdesc);
5225  new_desc->Assign(*desc_it);
5226  s_AddUnverifiedType(new_desc->SetUser(), type);
5227  changed_descs.push_back(make_pair(desc_it, new_desc));
5228  }
5229  }
5230 
5231  if (changed_descs.empty()) {
5232  CRef<CSeqdesc> new_desc(new CSeqdesc);
5233  s_AddUnverifiedType(new_desc->SetUser(), type);
5234  m_QualsChangedCount++;
5235 
5236  CRef<CCmdComposite> cmd(new CCmdComposite("Create Unverified user object"));
5237  cmd->AddCommand(*(new CCmdCreateDesc(bsh.GetSeq_entry_Handle(), *new_desc)));
5238  m_DataIter->RunCommand(cmd, m_CmdComposite);
5239  }
5240  else {
5241  CRef<CCmdComposite> cmd(new CCmdComposite("Update Unverified user object"));
5242  for (auto& it : changed_descs) {
5243  CRef<CCmdChangeSeqdesc> chg_cmd(new CCmdChangeSeqdesc(it.first.GetSeq_entry_Handle(), *it.first, *it.second));
5244  cmd->AddCommand(*chg_cmd);
5245  m_QualsChangedCount++;
5246  }
5247  m_DataIter->RunCommand(cmd, m_CmdComposite);
5248  }
5249 
5250  if (m_QualsChangedCount) {
5252  log << m_QualsChangedCount << ";adding new Unverified user object ";
5253  x_LogFunction(log);
5254  }
5255 }
5256 
5258 {
5259  switch (type) {
5261  user.AddUnverifiedOrganism();
5262  break;
5264  user.AddUnverifiedFeature();
5265  break;
5268  break;
5270  user.AddUnverifiedContaminant();
5271  break;
5272  default:
5273  break;
5274  }
5277  }
5278 }
5279 
5280 bool CMacroFunction_AddUnverified::x_ValidArguments() const
5281 {
5282  return (m_Args.size() == 1 && m_Args[0]->IsString());
5283 }
5284 
5285 
5286 ///////////////////////////////////////////////////////////////////////////////
5287 /// class CMacroFunction_ParseToDBLink
5288 /// ParseToDBLink(text|src_field, dblink, capitalization, existing_text_opt, delimiter)
5289 ///
5290 DEFINE_MACRO_FUNCNAME(CMacroFunction_ParseToDBLink, "ParseToDBLink")
5291 void CMacroFunction_ParseToDBLink::TheFunction()
5292 {
5293  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
5294  const CBioseq* bseq = dynamic_cast<const CBioseq*>(obj.GetPointer());
5295  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
5296  if (!scope || !bseq || bseq->IsAa())
5297  return;
5298 
5299  CObjectInfo oi = m_DataIter->GetEditedObject();
5300  size_t index = 0;
5301 
5302  CMQueryNodeValue text_holder;
5303  string text_portion;
5304 
5305  CMQueryNodeValue::TObs res_oi;
5306  if (m_Args[index]->IsString()) {
5307  const string& field = m_Args[index]->GetString();
5308  ResolveIdentToSimple(oi, field, text_holder);
5309  GetFieldsByName(&res_oi, oi, field);
5310  }
5311  else if (m_Args[index]->AreObjects()) {
5312  res_oi = m_Args[index]->GetObjects();
5313  if (!res_oi.empty()) {
5314  ResolveIdentToSimple(res_oi.front().field, kEmptyStr, text_holder);
5315  }
5316  }
5317  else if (m_Args[index]->IsRef()) {
5318  CMQueryNodeValue& objs = m_Args[index].GetNCObject();
5319  objs.Dereference();
5320 
5321  if (objs.GetDataType() == CMQueryNodeValue::eObjects) {
5322  res_oi = objs.GetObjects();
5323  if (!res_oi.empty()) {
5324  ResolveIdentToSimple(res_oi.front().field, kEmptyStr, text_holder);
5325  }
5326  }
5327  else if (objs.GetDataType() == CMQueryNodeValue::eString) {
5328  text_portion = objs.GetString();
5329  }
5330  }
5331 
5332  if (text_holder.GetDataType() == CMQueryNodeValue::eString && text_portion.empty()) {
5333  text_portion = text_holder.GetString();
5334  }
5335 
5336  if (text_portion.empty())
5337  return;
5338 
5339  // find dblink
5340  string dblink;
5341  if (m_Args[++index]->IsString()) {
5342  dblink = m_Args[index]->GetString();
5343  }
5344 
5345  if (dblink.empty())
5346  return;
5347 
5348  string capitalization = m_Args[++index]->GetString();
5349  string action_type = m_Args[++index]->GetString();
5350  string delimiter = (++index < m_Args.size()) ? m_Args[index]->GetString() : kEmptyStr;
5352 
5353  ECapChange cap_change = NMacroUtil::ConvertStringtoCapitalOption(capitalization);
5354  CSeq_entry_Handle seh = m_DataIter->GetSEH();
5355  FixCapitalizationInString(seh, text_portion, cap_change);
5356 
5358 
5359  vector<pair<CSeqdesc_CI, CRef<CSeqdesc>>> changed_descs;
5360  CBioseq_Handle bsh = m_DataIter->GetBioseqHandle();
5361  if (!bsh)
5362  return;
5363 
5364  for (CSeqdesc_CI desc_it(bsh, CSeqdesc::e_User); desc_it; ++desc_it) {
5365  if (desc_it->GetUser().GetType().IsStr() && desc_it->GetUser().GetType().GetStr() == "DBLink") {
5366  CRef<CSeqdesc> new_desc(new CSeqdesc);
5367  new_desc->Assign(*desc_it);
5368 
5369  bool found_user_field = false;
5370  EDIT_EACH_USERFIELD_ON_USEROBJECT(user_it, new_desc->SetUser()) {
5371  CUser_field& field = **user_it;
5372  if (field.GetLabel().IsStr() && NStr::Equal(field.GetLabel().GetStr(), dblink) && field.IsSetData()) {
5373  found_user_field = true;
5374  if (field.GetData().IsStrs()) {
5375  if (existing_text == edit::eExistingText_add_qual) {
5376  s_AddNewDBlinkValue(field, text_portion);
5377  m_QualsChangedCount++;
5378  }
5379  else if (existing_text == edit::eExistingText_replace_old) {
5380  // apply the same logic as in SetStrinQual:
5381  // keep the first element, update it and delete the rest
5382  field.SetData().Reset();
5383  field.ResetNum();
5384  s_AddNewDBlinkValue(field, text_portion);
5385  m_QualsChangedCount++;
5386 
5387  }
5388  else {
5389  // update all of them
5390  for (auto& it : field.SetData().SetStrs()) {
5391  string orig_value = it;
5392  if (edit::AddValueToString(orig_value, text_portion, existing_text)) {
5393  it = orig_value;
5394  m_QualsChangedCount++;
5395  }
5396  }
5397  }
5398  }
5399  }
5400  }
5401 
5402  if (!found_user_field && s_AddNewUserField(new_desc, dblink, text_portion)){
5403  m_QualsChangedCount++;
5404  }
5405  changed_descs.push_back(make_pair(desc_it, new_desc));
5406  }
5407  }
5408 
5409  if (changed_descs.empty()) {
5410  CRef<CSeqdesc> new_desc(new CSeqdesc);
5411  new_desc->SetUser().SetType().SetStr("DBLink");
5412  if (s_AddNewUserField(new_desc, dblink, text_portion))
5413  m_QualsChangedCount++;
5414 
5415  cmd.Reset(new CCmdComposite("Create DBLink user object"));
5416  cmd->AddCommand(*(new CCmdCreateDesc(bsh.GetSeq_entry_Handle(), *new_desc)));
5417  }
5418  else if (!changed_descs.empty()) {
5419  cmd.Reset(new CCmdComposite("Update DBLink user object"));
5420  for (auto& it : changed_descs) {
5421  CRef<CCmdChangeSeqdesc> chg_cmd(new CCmdChangeSeqdesc(it.first.GetSeq_entry_Handle(), *it.first, *it.second));
5422  cmd->AddCommand(*chg_cmd);
5423  }
5424  }
5425 
5426  if (m_QualsChangedCount) {
5427  m_DataIter->RunCommand(cmd, m_CmdComposite);
5428 
5429  TChangedQuals report;
5430  report["parsing text to " + dblink] = m_QualsChangedCount;
5431  CRef<IFunctionLog> fnc_log(new CGeneralFuncLog(report));
5432  x_LogChangedQuals(fnc_log);
5433  }
5434 }
5435 
5436 bool CMacroFunction_ParseToDBLink::x_ValidArguments() const
5437 {
5438  if (m_Args.size() > 5 || m_Args.size() < 4) {
5439  return false;
5440  }
5441  if (!(m_Args[0]->IsString() || m_Args[0]->AreObjects() || m_Args[0]->IsRef()))
5442  return false;
5443 
5444  for (size_t index = 1; index < m_Args.size(); ++index) {
5445  if (m_Args[index]->GetDataType() != CMQueryNodeValue::eString)
5446  return false;
5447  }
5448  return true;
5449 }
5450 
5451 
5452 ///////////////////////////////////////////////////////////////////////////////
5453 /// class CMacroFunction_AddorSetContElement
5454 /// Usage:
5455 /// o = Resolve("org.orgname.mod") where o.subtype = "strain";
5456 /// SetModifier(o, "org.orgname.mod", "strain", newvalue, existing_text, delimiter, remove_blank);
5457 /// SetGBQualifier(o, container_path, gb_qualifier, newvalue, existing_text, delimiter, remove_blank);
5458 /// The last two parameters are optional
5459 ///
5462 
5464 {
5465  size_t index = 2;
5466  const string& subtype_name = m_Args[index]->GetString();
5467  const string& newValue = NMacroUtil::GetStringValue(m_Args[++index]);
5468  const string& action_type = m_Args[++index]->GetString();
5469  string delimiter;
5470  bool remove_field = false;
5471  x_GetOptionalArgs(delimiter, remove_field, index);
5472 
5473  CObjectInfo oi = m_DataIter->GetEditedObject();
5474  CMQueryNodeValue::TObs res_oi = m_Args[0]->GetObjects();
5476 
5477  if (!newValue.empty()) {
5478  vector<string> new_values;
5479  if (res_oi.empty() || existing_text == edit::eExistingText_add_qual) { // there are no container elements(modifiers|gb qualifiers) of this kind
5480 
5481  CConstRef<CObject> object = m_DataIter->GetScopedObject().object;
5482  const CBioSource* const_bsrc = dynamic_cast<const CBioSource*>(object.GetPointer());
5483  const CSeq_feat* const_feat = dynamic_cast<const CSeq_feat*>(object.GetPointer());
5484  if (const_bsrc && m_IsBiosrc) {
5485  x_AddBioSrcModifier(subtype_name, newValue);
5486  }
5487  else if (const_feat && !m_IsBiosrc) {
5489  m_QualsChangedCount += s_AddGBQualifier(*seqfeat, subtype_name, newValue);
5490  }
5491  new_values.push_back(newValue);
5492 
5493  }
5494  else {
5495  if (existing_text == edit::eExistingText_leave_old) {
5496  return;
5497  }
5498 
5499  for (auto&& it : res_oi) {
5500  CObjectInfo obj = it.field;
5501  TMemberIndex index = 2;
5502 
5503  if (NMacroUtil::IsSatelliteSubfield(subtype_name)) {
5504  CObjectInfo value_oi = obj.GetClassMemberIterator(index).GetMember();
5506 
5507  string orig_value = value_oi.GetPrimitiveValueString();
5508  string sat_type = CMacroFunction_SatelliteFields::s_GetSatelliteType(orig_value);
5509  string sat_name = CMacroFunction_SatelliteFields::s_GetSatelliteName(orig_value);
5510 
5511  if (subtype_name == kSatelliteName) {
5512  if (edit::AddValueToString(sat_name, newValue, existing_text)) {
5513  string sat_value = CMacroFunction_SatelliteFields::s_MakeSatellite(sat_type, sat_name);
5514  SetQualStringValue(value_oi, sat_value);
5515  new_values.push_back(sat_value);
5516  }
5517  } else if (subtype_name == kSatelliteType) {
5518  string orig_sat_type = sat_type;
5519  if (edit::AddValueToString(sat_type, newValue, existing_text)) {
5520  auto found_it = find(kSatelliteTypes.begin(), kSatelliteTypes.end(), sat_type);
5521  bool good_type = (found_it != kSatelliteTypes.end()) ? true : false;
5522 
5523  string sat_value;
5524  if (good_type) {
5525  sat_value = CMacroFunction_SatelliteFields::s_MakeSatellite(sat_type, sat_name);
5526  }
5527  else {
5528  if (!sat_name.empty()) {
5529  sat_name = sat_type + ":" + sat_name;
5530  }
5531  else {
5532  sat_name = sat_type;
5533  }
5534  sat_value = CMacroFunction_SatelliteFields::s_MakeSatellite(orig_sat_type, sat_name);
5535  }
5536  SetQualStringValue(value_oi, sat_value);
5537  new_values.push_back(sat_value);
5538  }
5539  }
5540  }
5541  else if (NMacroUtil::IsMobileElementTSubfield(subtype_name)) {
5542  CObjectInfo value_oi = obj.GetClassMemberIterator(index).GetMember();
5544 
5545  string orig_value = value_oi.GetPrimitiveValueString();
5548 
5549  if (subtype_name == kMobileElementTName) {
5550  if (edit::AddValueToString(met_name, newValue, existing_text)) {
5551  string met_value = CMacroFunction_MobileElementTypeFields::s_MakeMobileElementT(met_type, met_name);
5552  SetQualStringValue(value_oi, met_value);
5553  new_values.push_back(met_value);
5554  }
5555  }
5556  else if (subtype_name == kMobileElementTType) {
5557  string orig_met_type = met_type;
5558  if (edit::AddValueToString(met_type, newValue, existing_text)) {
5559  auto found_it = find(kMobileETypeTypes.begin(), kMobileETypeTypes.end(), met_type);
5560  bool good_type = (found_it != kMobileETypeTypes.end()) ? true : false;
5561 
5562  string met_value;
5563  if (good_type) {
5564  met_value = CMacroFunction_MobileElementTypeFields::s_MakeMobileElementT(met_type, met_name);
5565  }
5566  else {
5567  // if it's a bad type, don't insert it
5568  met_value = CMacroFunction_MobileElementTypeFields::s_MakeMobileElementT(orig_met_type, met_name);
5569  }
5570  SetQualStringValue(value_oi, met_value);
5571  new_values.push_back(met_value);
5572  }
5573  }
5574  }
5575  else {
5576  CObjectInfoMI mem = obj.GetClassMemberIterator(index);
5577  string field_name = mem.GetMemberInfo()->GetId().GetName();
5578 
5579  if (!ResolveAndSetSimpleTypeValue(obj, field_name, *m_Args[3], existing_text)) {
5580  return;
5581  }
5582  m_QualsChangedCount++;
5583  CMQueryNodeValue new_val;
5584  GetSimpleTypeValue(obj, field_name, new_val);
5585  if (new_val.GetDataType() == CMQueryNodeValue::eString) {
5586  new_values.push_back(new_val.GetString());
5587  }
5588  }
5589  }
5590  }
5591 
5592  if (m_QualsChangedCount) {
5593  m_DataIter->SetModified();
5595  log << m_DataIter->GetBestDescr();
5596  for (size_t i = 0; i < new_values.size(); ++i) {
5597  log << " '" << new_values[i] << "' has been set as a new value";
5598  }
5599  x_LogFunction(log);
5600  }
5601  }
5602  else if (remove_field) {
5603  if (!res_oi.empty()) {
5604  if (NMacroUtil::IsSatelliteSubfield(subtype_name)) {
5605  for (auto&& it : res_oi) {
5606  TMemberIndex index = 2;
5607  CObjectInfo value_oi = it.field.GetClassMemberIterator(index).GetMember();
5609 
5610  string newValue;
5611  string orig_value = value_oi.GetPrimitiveValueString();
5612  if (subtype_name == kSatelliteName) {
5614  }
5615  else if (subtype_name == kSatelliteType) {
5617  }
5618 
5619  if (!newValue.empty()) {
5620  SetQualStringValue(value_oi, newValue);
5621  }
5622  else {
5623  // remove the object
5624  if (RemoveFieldByName(it)) {
5625  m_QualsChangedCount++;
5626  }
5627  }
5628  }
5629  }
5630  else if (NMacroUtil::IsMobileElementTSubfield(subtype_name)) {
5631  for (auto&& it : res_oi) {
5632  TMemberIndex index = 2;
5633  CObjectInfo value_oi = it.field.GetClassMemberIterator(index).GetMember();
5635 
5636  string newValue;
5637  string orig_value = value_oi.GetPrimitiveValueString();
5638  if (subtype_name == kMobileElementTName) {
5640  }
5641  else if (subtype_name == kMobileElementTType) {
5643  }
5644 
5645  if (!newValue.empty()) {
5646  SetQualStringValue(value_oi, newValue);
5647  }
5648  else {
5649  // remove the object
5650  if (RemoveFieldByName(it)) {
5651  m_QualsChangedCount++;
5652  }
5653  }
5654  }
5655  }
5656  else {
5657  for (auto&& it : res_oi) {
5658  if (RemoveFieldByName(it)) {
5659  m_QualsChangedCount++;
5660  }
5661  }
5662  }
5663  }
5664 
5665  if (m_QualsChangedCount) {
5666  CConstRef<CObject> const_obj = m_DataIter->GetScopedObject().object;
5667  CCleanup cleanup;
5668 
5669  if (dynamic_cast<const CSeq_feat*>(const_obj.GetPointer())) {
5671  cleanup.BasicCleanup(*seq_feat);
5672  }
5673  else if (dynamic_cast<const CBioSource*>(const_obj.GetPointer())) {
5675  cleanup.BasicCleanup(*bsrc);
5676  }
5677 
5678  m_DataIter->SetModified();
5680  log << m_DataIter->GetBestDescr() << ": removed " << m_QualsChangedCount << " modifiers";
5681  x_LogFunction(log);
5682  }
5683  }
5684 }
5685 
5687 {
5688  // 1 - objects
5689  // 2 - asn path to the modifier's container
5690  // 3 - type of modifier
5691  // 4 - value to be set, simple type
5692  // 5 - handling existint text
5693  // 6 - delimiter (optional)
5694  // 7 - remove blank (optional)
5695  size_t arg_size = m_Args.size();
5696  if (arg_size < 5 || arg_size > 7)
5697  return false;
5698 
5699  CMQueryNodeValue& objs = m_Args[0].GetNCObject();
5700  objs.Dereference();
5701  if (!objs.AreObjects() && !objs.IsNotSet())
5702  return false;
5703 
5704  if (!m_Args[1]->IsString() || !m_Args[2]->IsString()) return false;
5705 
5706  NMacroUtil::GetPrimitiveFromRef(m_Args[3].GetNCObject());
5707  bool type_ok = m_Args[3]->IsString() || m_Args[3]->IsInt() || m_Args[3]->IsDouble();
5708  if (!type_ok) return false;
5709 
5710  if (!m_Args[4]->IsString()) return false;
5711 
5712  if (arg_size > 5 && (!m_Args[5]->IsString() && !m_Args[5]->IsBool())) return false;
5713 
5714  if (arg_size > 6 && !m_Args[6]->IsBool()) return false;
5715  return true;
5716 }
5717 
5718 void CMacroFunction_AddorSetContElement::x_AddBioSrcModifier(const string& subtype, const string& newValue)
5719 {
5720  CObjectInfo oi = m_DataIter->GetEditedObject();
5722  if (!bsrc)
5723  return;
5724 
5725  if (CSubSource::IsValidSubtypeName(subtype)) {
5726  int subtype_val = CSubSource::GetSubtypeValue(subtype);
5727  if (subtype_val == CSubSource::eSubtype_other) {
5728  if (m_Args[1]->GetString() == "subtype" && s_AddSrcSubSource(*bsrc, subtype_val, newValue))
5730  else if (s_AddSrcOrgMod(*bsrc, subtype_val, newValue))
5732  }
5733  else if (s_AddSrcSubSource(*bsrc, subtype_val, newValue)) {
5735  }
5736  }
5737  else if (COrgMod::IsValidSubtypeName(subtype)) {
5738  int subtype_val = COrgMod::GetSubtypeValue(subtype);
5739  if (s_AddSrcOrgMod(*bsrc, subtype_val, newValue)) {
5741  }
5742  }
5743  else {
5744  NCBI_THROW(CException, eUnknown, "Wrong subtype name: " + subtype);
5745  }
5746 }
5747 
5748 int CMacroFunction_AddorSetContElement::s_AddGBQualifier(CSeq_feat& feat, const string& qual_name, const string& newValue)
5749 {
5750  int count = 0;
5751  string qualifier = qual_name;
5752  string apply_value = newValue;
5753 
5754  if (qual_name == kSatelliteName) {
5756  qualifier = "satellite";
5757  }
5758  else if (qual_name == kSatelliteType) {
5760  qualifier = "satellite";
5761  }
5762  else if (qual_name == kMobileElementTName) {
5764  qualifier = kMobileElementTQual;
5765  }
5766  else if (qual_name == kMobileElementTType) {
5768  qualifier = kMobileElementTQual;
5769  }
5770 
5771  if (!apply_value.empty()) {
5772  feat.AddQualifier(qualifier, apply_value);
5773  count++;
5774  }
5775 
5776  return count;
5777 }
5778 
5780 {
5781  bool added = false;
5782  CRef<COrgMod> orgmod(new COrgMod());
5783  orgmod->SetSubtype(subtype);
5784  orgmod->SetSubname(value);
5785  if (!bsrc.IsSetOrgname()) {
5786  CRef<COrgName> orgname(new COrgName());
5787  orgname->SetMod().push_back(orgmod);
5788  bsrc.SetOrg().SetOrgname(*orgname);
5789  added = true;
5790  }
5791  else {
5792  bsrc.SetOrg().SetOrgname().SetMod().push_back(orgmod);
5793  added = true;
5794  }
5795  return added;
5796 }
5797 
5799 {
5800  bool added = false;
5801  CRef<CSubSource> sub_src(new CSubSource());
5802  sub_src->SetSubtype(subtype);
5803  sub_src->SetName(value);
5804  bsrc.SetSubtype().push_back(sub_src);
5805  added = true;
5806 
5807  return added;
5808 }
5809 
5810 ///////////////////////////////////////////////////////////////////////////////
5811 /// class CMacroFunction_SatelliteFields
5812 /// SATELLITE_NAME()
5813 /// SATELLITE_TYPE()
5814 ///
5817 
5819 {
5820  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
5821  const CSeq_feat* feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
5822  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
5823  m_Result->SetNotSet();
5824  if (!feat || !scope || !feat->IsSetQual())
5825  return;
5826 
5827  const string& qual_value = feat->GetNamedQual("satellite");
5828  if (!qual_value.empty()) {
5829  string value;
5830  switch (m_FieldType) {
5831  case eSatelliteType:
5832  value = s_GetSatelliteType(qual_value);
5833  break;
5834  case eSatelliteName:
5835  value = s_GetSatelliteName(qual_value);
5836  break;
5837  }
5838 
5839  if (m_Nested == eNotNested) { // return a string
5840  m_Result->SetString(value);
5841  }
5842  else {
5843  // return a reference to a CMQueryNodeValue of type string
5845  new_node->SetString(value);
5846  m_Result->SetRef(new_node);
5847  }
5848  }
5849 }
5850 
5852 {
5853  SIZE_TYPE pos = NStr::FindNoCase(value, ":");
5854  if (pos != NPOS) {
5855  return value.substr(0, pos);
5856  }
5857 
5858  auto it = find(kSatelliteTypes.begin(), kSatelliteTypes.end(), value);
5859  return (it != kSatelliteTypes.end()) ? value : kEmptyStr;
5860 }
5861 
5863 {
5864  SIZE_TYPE pos = NStr::FindNoCase(value, ":");
5865  if (pos != NPOS) {
5866  return value.substr(pos + 1, NPOS);
5867  }
5868 
5869  auto it = find(kSatelliteTypes.begin(), kSatelliteTypes.end(), value);
5870  return (it != kSatelliteTypes.end()) ? kEmptyStr : value;
5871 }
5872 
5873 string CMacroFunction_SatelliteFields::s_MakeSatellite(const string& type, const string& name)
5874 {
5875  string new_type = type;
5876  string new_name;
5877  if (!name.empty()) {
5878  new_name = ":" + name;
5879  }
5880  if (type.empty()) {
5881  new_type = kSatelliteTypes.front();
5882  }
5883  else {
5884  auto found_it = find(kSatelliteTypes.begin(), kSatelliteTypes.end(), type);
5885  bool good_type = (found_it != kSatelliteTypes.end()) ? true : false;
5886 
5887  if (!good_type) {
5888  new_type = kSatelliteTypes.front();
5889  new_name = ":" + type + new_name;
5890  }
5891  }
5892  return new_type + new_name;
5893 }
5894 
5896 {
5897  return (m_Args.empty());
5898 }
5899 
5900 ///////////////////////////////////////////////////////////////////////////////
5901 /// class CMacroFunction_MobileElementTypeFields
5902 /// MOBILE_ELEMENTTYPE_NAME()
5903 /// MOBILE_ELEMENTTYPE_TYPE()
5904 ///
5905 DEFINE_MACRO_FUNCNAME(CMacroFunction_MobileElementType, "MOBILE_ELEMENTTYPE_TYPE")
5906 DEFINE_MACRO_FUNCNAME(CMacroFunction_MobileElementName, "MOBILE_ELEMENTTYPE_NAME")
5907 
5909 {
5910  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
5911  const CSeq_feat* feat = dynamic_cast<const CSeq_feat*>(obj.GetPointer());
5912  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
5913  m_Result->SetNotSet();
5914  if (!feat || !scope || !feat->IsSetQual())
5915  return;
5916 
5917  const string& qual_value = feat->GetNamedQual(kMobileElementTQual);
5918  if (!qual_value.empty()) {
5919  string value;
5920  switch (m_FieldType) {
5921  case eMobileElemTType:
5922  value = s_GetMobileElemTType(qual_value);
5923  break;
5924  case eMobileElemTName:
5925  value = s_GetMobileElemTName(qual_value);
5926  break;
5927  }
5928 
5929  if (m_Nested == eNotNested) { // return a string
5930  m_Result->SetString(value);
5931  }
5932  else {
5933  // return a reference to a CMQueryNodeValue of type string
5935  new_node->SetString(value);
5936  m_Result->SetRef(new_node);
5937  }
5938  }
5939 }
5940 
5942 {
5943  SIZE_TYPE pos = NStr::FindNoCase(value, ":");
5944  if (pos != NPOS) {
5945  string type = value.substr(0, pos);
5946  auto it = find(kMobileETypeTypes.begin(), kMobileETypeTypes.end(), type);
5947  return (it != kMobileETypeTypes.end()) ? type : kEmptyStr;
5948  }
5949 
5950  auto it = find(kMobileETypeTypes.begin(), kMobileETypeTypes.end(), value);
5951  return (it != kMobileETypeTypes.end()) ? value : kEmptyStr;
5952 }
5953 
5955 {
5956  SIZE_TYPE pos = NStr::FindNoCase(value, ":");
5957  if (pos != NPOS) {
5958  string type = value.substr(0, pos);
5959  string name = value.substr(pos + 1, NPOS);
5960  auto it = find(kMobileETypeTypes.begin(), kMobileETypeTypes.end(), type);
5961  return (it != kMobileETypeTypes.end()) ? name : value;
5962  }
5963 
5964  auto it = find(kMobileETypeTypes.begin(), kMobileETypeTypes.end(), value);
5965  return (it != kMobileETypeTypes.end()) ? kEmptyStr : value;
5966 }
5967 
5969 {
5970  // don't add a default type
5971  string value;
5972  if (!type.empty()) {
5973  auto found_it = find(kMobileETypeTypes.begin(), kMobileETypeTypes.end(), type);
5974  bool good_type = (found_it != kMobileETypeTypes.end()) ? true : false;
5975 
5976  if (good_type) {
5977  if (!name.empty()) {
5978  value = type + ":" + name;
5979  }
5980  else {
5981  value = type;
5982  }
5983  }
5984  }
5985  else {
5986  value = name;
5987  }
5988  return value;
5989 }
5990 
5992 {
5993  return (m_Args.empty());
5994 }
5995 
5996 
5997 ///////////////////////////////////////////////////////////////////////////////
5998 /// class CMacroFunction_EditSubfield
5999 /// EditSubfield(obj, subfield, find_text, repl_text, location, case_sensitive, is_regex)
6000 DEFINE_MACRO_FUNCNAME(CMacroFunction_EditSubfield, "EditSubfield")
6001  void CMacroFunction_EditSubfield::TheFunction()
6002 {
6003  size_t index = 1;
6004  const string& subfield = m_Args[1]->GetString();
6005  if (subfield.empty())
6006  NCBI_THROW(CException, eUnknown, " Empty subfield is specified");
6007 
6008  const string& find_txt = NMacroUtil::GetStringValue(m_Args[++index]);
6009  string repl_txt = NMacroUtil::GetStringValue(m_Args[++index]);
6010  const string& location = m_Args[++index]->GetString();
6011  bool case_sensitive = m_Args[++index]->GetBool();
6012  bool is_regex = (++index < m_Args.size()) ? m_Args[index]->GetBool() : false;
6013 
6015  if (m_Args[0]->AreObjects()) {
6016  objs = m_Args[0]->GetObjects();
6017  }
6018  else if (m_Args[0]->IsRef()) {
6019  x_GetObjectsFromRef(objs, 0);
6020  }
6021  if (objs.empty()) {
6022  return;
6023  }
6024 
6026  for (auto&& it : objs) {
6027  CObjectInfo value_oi = it.field;
6029 
6030  string orig_value = value_oi.GetPrimitiveValueString();
6031  string newValue;
6032  if (NMacroUtil::IsSatelliteSubfield(subfield)) {
6033  string sat_type = CMacroFunction_SatelliteFields::s_GetSatelliteType(orig_value);
6034  string sat_name = CMacroFunction_SatelliteFields::s_GetSatelliteName(orig_value);
6035  if (subfield == kSatelliteName) {
6036  if (CMacroFunction_EditStringQual::s_EditText(sat_name, find_txt, repl_txt, loc, case_sensitive, is_regex)) {
6037  newValue = CMacroFunction_SatelliteFields::s_MakeSatellite(sat_type, sat_name);
6038  SetQualStringValue(value_oi, newValue);
6039  }
6040  }
6041  else if (subfield == kSatelliteType) {
6042  string orig_sat_type = sat_type;
6043  if (CMacroFunction_EditStringQual::s_EditText(sat_type, find_txt, repl_txt, loc, case_sensitive, is_regex)) {
6044  auto found_it = find(kSatelliteTypes.begin(), kSatelliteTypes.end(), sat_type);
6045  bool good_type = (found_it != kSatelliteTypes.end()) ? true : false;
6046 
6047  if (good_type) {
6048  newValue = CMacroFunction_SatelliteFields::s_MakeSatellite(sat_type, sat_name);
6049  }
6050  else {
6051  if (!sat_name.empty())
6052  sat_name = sat_type + ":" + sat_name;
6053  newValue = CMacroFunction_SatelliteFields::s_MakeSatellite(orig_sat_type, sat_name);
6054  }
6055  SetQualStringValue(value_oi, newValue);
6056  }
6057  }
6058  }
6059  else if (NMacroUtil::IsMobileElementTSubfield(subfield)) {
6062  if (subfield == kMobileElementTName) {
6063  if (CMacroFunction_EditStringQual::s_EditText(met_name, find_txt, repl_txt, loc, case_sensitive, is_regex)) {
6064  newValue = CMacroFunction_MobileElementTypeFields::s_MakeMobileElementT(met_type, met_name);
6065  SetQualStringValue(value_oi, newValue);
6066  }
6067  }
6068  else if (subfield == kMobileElementTType) {
6069  string orig_met_type = met_type;
6070  if (CMacroFunction_EditStringQual::s_EditText(met_type, find_txt, repl_txt, loc, case_sensitive, is_regex)) {
6071  auto found_it = find(kMobileETypeTypes.begin(), kMobileETypeTypes.end(), met_type);
6072  bool good_type = (found_it != kMobileETypeTypes.end()) ? true : false;
6073 
6074  if (good_type) {
6075  newValue = CMacroFunction_MobileElementTypeFields::s_MakeMobileElementT(met_type, met_name);
6076  }
6077  else {
6078  newValue = CMacroFunction_MobileElementTypeFields::s_MakeMobileElementT(orig_met_type, met_name);
6079  }
6080  SetQualStringValue(value_oi, newValue);
6081  }
6082  }
6083  } else {
6084  auto part = NMacroUtil::GetSVPartFromString(subfield);
6085  if (part != NMacroUtil::eSV_Error) {
6086  string inst, coll, id;
6087  COrgMod::ParseStructuredVoucher(orig_value, inst, coll, id);
6088 
6089  switch (part) {
6090  case NMacroUtil::eSV_Inst:
6091  CMacroFunction_EditStringQual::s_EditText(inst, find_txt, repl_txt, loc, case_sensitive, is_regex);
6092  break;
6093  case NMacroUtil::eSV_Coll:
6094  CMacroFunction_EditStringQual::s_EditText(coll, find_txt, repl_txt, loc, case_sensitive, is_regex);
6095  break;
6097  CMacroFunction_EditStringQual::s_EditText(id, find_txt, repl_txt, loc, case_sensitive, is_regex);
6098  break;
6099  default: break;
6100  }
6101  newValue = COrgMod::MakeStructuredVoucher(inst, coll, id);
6102  SetQualStringValue(value_oi, newValue);
6103  }
6104  }
6105  }
6106 
6107  if (m_QualsChangedCount) {
6108  m_DataIter->SetModified();
6110  log << m_DataIter->GetBestDescr() << ": edited " << m_QualsChangedCount << " qualifiers, replaced " << find_txt;
6111  if (NStr::IsBlank(repl_txt)) {
6112  repl_txt.assign("''");
6113  }
6114  log << " with " << repl_txt;
6115  x_LogFunction(log);
6116  }
6117 }
6118 
6119 bool CMacroFunction_EditSubfield::x_ValidArguments() const
6120 {
6121  if (m_Args.size() != 7)
6122  return false;
6123 
6124  bool first_ok = m_Args[0]->AreObjects() || m_Args[0]->IsRef();
6125  if (!first_ok || !m_Args[1]->IsString()) {
6126  return false;
6127  }
6128 
6129  for (size_t index = 2; index < 4; index++) {
6130  if (!m_Args[index]->IsString() && !m_Args[index]->IsInt()) {
6131  return false;
6132  }
6133  }
6134  return (m_Args[4]->IsString() && m_Args[5]->IsBool() && m_Args[6]->IsBool());
6135 }
6136 
6137 ///////////////////////////////////////////////////////////////////////////////
6138 /// class CMacroFunction_RemoveSubfield
6139 /// RemoveSubField(object, field_name)
6140 ///
6141 DEFINE_MACRO_FUNCNAME(CMacroFunction_RemoveSubfield, "RemoveSubField")
6142 
6143 void CMacroFunction_RemoveSubfield::TheFunction()
6144 {
6145  const string& subfield = m_Args[1]->GetString();
6146  if (subfield.empty())
6147  NCBI_THROW(CException, eUnknown, " Empty subfield is specified");
6148 
6150  if (m_Args[0]->AreObjects()) {
6151  objs = m_Args[0]->GetObjects();
6152  }
6153  else if (m_Args[0]->IsRef()) {
6154  x_GetObjectsFromRef(objs, 0);
6155  }
6156  if (objs.empty()) {
6157  return;
6158  }
6159 
6160  for (auto&& it : objs) {
6161  CObjectInfo res_oi = it.field;
6162  _ASSERT(res_oi.GetTypeFamily() == eTypeFamilyClass);
6163 
6164  TMemberIndex index = 2;
6165  CObjectInfo value_oi = res_oi.GetClassMemberIterator(index).GetMember();
6167 
6168  string newValue;
6169  if (subfield == kSatelliteName) {
6171  }
6172  else if (subfield == kSatelliteType) {
6174  }
6175  else if (subfield == kMobileElementTName) {
6177  }
6178  else if (subfield == kMobileElementTType) {
6180  }
6181  else {
6182  auto part = NMacroUtil::GetSVPartFromString(subfield);
6183  if (part != NMacroUtil::eSV_Error) {
6184  string inst, coll, id;
6185  COrgMod::ParseStructuredVoucher(value_oi.GetPrimitiveValueString(), inst, coll, id);
6186 
6187  switch (part) {
6188  case NMacroUtil::eSV_Inst: inst.clear(); break;
6189  case NMacroUtil::eSV_Coll: coll.clear(); break;
6190  case NMacroUtil::eSV_Specid: id.clear(); break;
6191  default: break;
6192  }
6193  newValue = COrgMod::MakeStructuredVoucher(inst, coll, id);
6194  }
6195  }
6196 
6197  if (!newValue.empty()) {
6198  SetQualStringValue(value_oi, newValue);
6199  }
6200  else {
6201  // remove the object
6202  if (RemoveFieldByName(it)) {
6203  m_QualsChangedCount++;
6204  }
6205  }
6206  }
6207 
6208  if (m_QualsChangedCount) {
6209  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
6210  CRef<CScope> scope = m_DataIter->GetScopedObject().scope;
6211  CObjectInfo oi = m_DataIter->GetEditedObject();
6212  CCleanup cleanup;
6213  if (dynamic_cast<const CSeq_feat*>(obj.GetPointer())) {
6215  cleanup.BasicCleanup(*seq_feat);
6216  }
6217  else if (dynamic_cast<const CBioSource*>(obj.GetPointer())) {
6219  cleanup.BasicCleanup(*bsrc);
6220  }
6221 
6222  m_DataIter->SetModified();
6224  log << m_DataIter->GetBestDescr() << ": removed " << m_QualsChangedCount << " qualifiers";
6225  x_LogFunction(log);
6226  }
6227 }
6228 
6229 
6230 bool CMacroFunction_RemoveSubfield::x_ValidArguments() const
6231 {
6232  return m_Args.size() == 2 && (m_Args[0]->AreObjects() || m_Args[0]->IsRef()) && m_Args[1]->IsString();
6233 }
6234 
6235 ///////////////////////////////////////////////////////////////////////////////
6236 /// CMacroFunction_SetCodonsRecognized
6237 /// SetCodonsRecognized(field_name)
6238 /// The field_name specifies one of the primer sequences
6239 ///
6240 
6241 static bool s_IsATGC(char ch)
6242 {
6243  if (ch == 'A' || ch == 'T' || ch == 'G' || ch == 'C' || ch == 'U') {
6244  return true;
6245  }
6246  else {
6247  return false;
6248  }
6249 }
6250 
6251 
6252 static const string kAmbiguities = "MRSVWYHKDBN";
6253 static const string kReplacements[] = {
6254  "AC", "AG", "CG", "ACG", "AT", "CT", "ACT", "GT", "AGT", "CGT", "ACGT" };
6255 
6256 static const string s_GetExpansion(const string& ch)
6257 {
6258  size_t pos = NStr::Find(kAmbiguities, ch);
6259  if (pos != string::npos) {
6260  return kReplacements[pos];
6261  }
6262  else {
6263  return ch;
6264  }
6265 }
6266 
6267 
6268 static vector<string> ParseDegenerateCodons(string codon)
6269 {
6270  vector<string> replacements;
6271 
6272  if (codon.length() == 3 && s_IsATGC(codon.c_str()[0])) {
6273  string this_codon = codon.substr(0, 1);
6274  replacements.push_back(this_codon);
6275 
6276  for (int i = 1; i < 3; i++) {
6277  string ch = s_GetExpansion(codon.substr(i, 1));
6278  size_t num_now = replacements.size();
6279  // add copies for each expansion letter beyond the first
6280  for (unsigned int j = 1; j < ch.length(); j++) {
6281  for (unsigned int k = 0; k < num_now; k++) {
6282  string cpy = replacements[k];
6283  replacements.push_back(cpy);
6284  }
6285  }
6286  for (unsigned int k = 0; k < num_now; k++) {
6287  for (unsigned int j = 0; j < ch.length(); j++) {
6288  replacements[j * num_now + k].append(ch.substr(j, 1));
6289  }
6290  }
6291  }
6292  }
6293  else {
6294  replacements.push_back(codon);
6295  }
6296  return replacements;
6297 }
6298 
6299 DEFINE_MACRO_FUNCNAME(CMacroFunction_SetCodonsRecognized, "SetCodonsRecognized")
6300 void CMacroFunction_SetCodonsRecognized::TheFunction()
6301 {
6302  CObjectInfo oi = m_DataIter->GetEditedObject();
6304  if (!edit_feat) {
6305  return;
6306  }
6307 
6308  string value;
6309  if (m_Args[0]->IsRef()) {
6310  CMQueryNodeValue& parsed_obj = m_Args[0].GetNCObject();
6311  parsed_obj.Dereference();
6312  if (parsed_obj.GetDataType() != CMQueryNodeValue::eString) {
6313  return;
6314  }
6315  value = parsed_obj.GetString();
6316  }
6317  else if (m_Args[0]->IsString()) {
6318  value = m_Args[0]->GetString();
6319  }
6320 
6321  if (value.empty()) {
6322  return;
6323  }
6324 
6325  if (edit_feat->IsSetData() && edit_feat->GetData().IsRna()
6326  && edit_feat->GetData().GetRna().IsSetType()
6327  && edit_feat->GetData().GetRna().GetType() == CRNA_ref::eType_tRNA)
6328  {
6329  edit_feat->SetData().SetRna().SetExt().SetTRNA().ResetCodon();
6330 
6333  if (value.empty())
6334  return;
6335 
6336  vector<string> codons = ParseDegenerateCodons(value);
6337  for (unsigned int j = 0; j < codons.size(); j++)
6338  {
6340  if (val > -1)
6341  {
6342  edit_feat->SetData().SetRna().SetExt().SetTRNA().SetCodon().push_back(val);
6343  }
6344  }
6345 
6346  m_DataIter->SetModified();
6347 
6349  log << m_DataIter->GetBestDescr() << ": set codons-recognized";
6350  x_LogFunction(log);
6351  }
6352 }
6353 
6354 bool CMacroFunction_SetCodonsRecognized::x_ValidArguments() const
6355 {
6356  return (m_Args.size() == 1 && (m_Args[0]->IsRef() || m_Args[0]->IsString()));
6357 }
6358 
6359 
6360 ///////////////////////////////////////////////////////////////////////////////
6361 /// class CMacroFunction_SetStructCommField
6362 /// SetStructCommField([obj_to_modify,] field_name, field_value, existing_text, delimiter, remove_blank)
6363 /// The last parameter is optional
6364 ///
6365 DEFINE_MACRO_FUNCNAME(CMacroFunction_SetStructCommField, "SetStructCommField")
6366 void CMacroFunction_SetStructCommField::TheFunction()
6367 {
6368  CConstRef<CObject> object = m_DataIter->GetScopedObject().object;
6369  const CBioseq* bioseq = dynamic_cast<const CBioseq*>(object.GetPointer());
6370  const CUser_object* user = dynamic_cast<const CUser_object*>(object.GetPointer());
6371  if (!(bioseq && bioseq->IsNa()) &&
6372  !(user && CComment_rule::IsStructuredComment(*user))) {
6373  return;
6374  }
6375 
6376  size_t index = 1;
6377  CMQueryNodeValue::EType type = m_Args[0]->GetDataType();
6379  --index;
6380  }
6381  const string& field_name = m_Args[index]->GetString();
6382  const string& field_value = m_Args[++index]->GetString();
6383  const string& existing_text_option = m_Args[++index]->GetString();
6384  string delimiter;
6385  bool remove_field = false;
6386  x_GetOptionalArgs(delimiter, remove_field, index);
6387 
6388  edit::EExistingText existing_text = NMacroUtil::ActionTypeToExistingTextOption(existing_text_option, delimiter);
6389  if (!field_value.empty()) {
6390  if (type == CMQueryNodeValue::eString && user) {
6391  CObjectInfo oi = m_DataIter->GetEditedObject();
6393  if (existing_text == edit::eExistingText_add_qual) {
6394  // add a new field to the structured comment
6395  user_object->AddField(field_name, field_value);
6396  m_QualsChangedCount++;
6397  }
6398  else {
6399  if (user_object->HasField(field_name)) {
6400  CUser_field& user_field = user_object->SetField(field_name);
6401  if (user_field.IsSetData() && user_field.GetData().IsStr()) {
6402  string orig_val = user_field.GetData().GetStr();
6403  if (AddValueToString(orig_val, field_value, existing_text)) {
6404  user_field.SetData().SetStr(orig_val);
6405  m_QualsChangedCount++;
6406  }
6407  }
6408  }
6409  else {
6410  // add a new field to the structured comment
6411  user_object->AddField(field_name, field_value);
6412  m_QualsChangedCount++;
6413  }
6414  }
6415 
6416  if (m_QualsChangedCount) {
6418  CCleanup::CleanupUserObject(*user_object);
6419  }
6420  }
6421  else if (bioseq) { // for creating new structured comment for the nucleotide sequence
6422  // if there is an object
6423  CMQueryNodeValue::TObs res_oi = m_Args[0]->GetObjects();
6424  if (res_oi.empty() || existing_text == edit::eExistingText_leave_old) {
6425  return;
6426  }
6427 
6428  CObjectInfo oi = m_DataIter->GetEditedObject();
6430  if (!edit_bseq) return;
6431 
6432  CSeqdesc* seqdesc = CTypeConverter<CSeqdesc>::SafeCast(res_oi.front().field.GetObjectPtr());
6433  if (!seqdesc) return;
6434 
6435  if (seqdesc->GetUser().HasField(field_name)) {
6436  CUser_field& user_field = seqdesc->SetUser().SetField(field_name);
6437  if (user_field.IsSetData()) {
6438  if (user_field.GetData().IsStr()) {
6439  string orig_val = user_field.GetData().GetStr();
6440  if (AddValueToString(orig_val, field_value, existing_text)) {
6441  user_field.SetData().SetStr(orig_val);
6442  m_QualsChangedCount++;
6443  }
6444  }
6445  else if (user_field.GetData().Which() == CUser_field::TData::e_not_set) {
6446  user_field.SetData().SetStr(field_value);
6447  m_QualsChangedCount++;
6448  }
6449  }
6450  }
6451  else {
6452  seqdesc->SetUser().AddField(field_name, field_value);
6453  m_QualsChangedCount++;
6454  }
6455 
6456  if (m_QualsChangedCount) {
6459  }
6460  }
6461 
6462  if (m_QualsChangedCount) {
6463  m_DataIter->SetModified();
6465  log << m_DataIter->GetBestDescr() << ": applied ('" << field_name << "', '" << field_value << "') field-value pair";
6466  x_LogFunction(log);
6467  }
6468  }
6469  else if (remove_field) {
6470  if (type == CMQueryNodeValue::eString && user) {
6471  CObjectInfo oi = m_DataIter->GetEditedObject();
6473  if (user_object && user_object->HasField(field_name) && user_object->RemoveNamedField(field_name)) {
6474  m_QualsChangedCount++;
6475  }
6476  }
6477  else if (bioseq) {
6478  CMQueryNodeValue::TObs res_oi = m_Args[0]->GetObjects();
6479  if (res_oi.empty() || existing_text == edit::eExistingText_leave_old) {
6480  return;
6481  }
6482 
6483  CObjectInfo oi = m_DataIter->GetEditedObject();
6485  if (!edit_bseq) return;
6486 
6487  CObjectInfo desc_oi = res_oi.front().field;
6489  if (!seqdesc) return;
6490 
6491  if (seqdesc->GetUser().HasField(field_name) && seqdesc->SetUser().RemoveNamedField(field_name)) {
6492  m_QualsChangedCount++;
6493  }
6494  }
6495 
6496  if (m_QualsChangedCount) {
6497  m_DataIter->SetModified();
6499  log << m_DataIter->GetBestDescr() << ": removed " << m_QualsChangedCount << " structured comment fields";
6500  x_LogFunction(log);
6501  }
6502  }
6503 }
6504 
6505 bool CMacroFunction_SetStructCommField::x_ValidArguments() const
6506 {
6507  if (m_Args.size() < 3 || m_Args.size() > 6)
6508  return false;
6509 
6510  if (m_Args[0]->IsRef()) {
6511  CMQueryNodeValue& objs = m_Args[0].GetNCObject();
6512  objs.Dereference();
6513  if (!objs.AreObjects() && !objs.IsNotSet())
6514  return false;
6515  }
6516  else if (!m_Args[0]->IsString()) {
6517  return false;
6518  }
6519 
6520  NMacroUtil::GetPrimitiveFromRef(m_Args[1].GetNCObject());
6521  for (size_t i = 1; i < m_Args.size(); ++i) {
6522  if (!m_Args[i]->IsString() && !m_Args[i]->IsBool()) {
6523  return false;
6524  }
6525  }
6526  return true;
6527 }
6528 
6529 
6530 ///////////////////////////////////////////////////////////////////////////////
6531 /// class CMacroFunction_SetStructCommDb
6532 /// SetStructCommDb(db_name, existing_text, delimiter, remove_blank)
6533 /// The last two parameters are optional
6535 
6537 {
6538  CConstRef<CObject> object = m_DataIter->GetScopedObject().object;
6539  const CBioseq* bioseq = dynamic_cast<const CBioseq*>(object.GetPointer());
6540  const CUser_object* user = dynamic_cast<const CUser_object*>(object.GetPointer());
6541  if (!(bioseq && bioseq->IsNa()) &&
6542  !(user && CComment_rule::IsStructuredComment(*user))) {
6543  return;
6544  }
6545 
6546  size_t index = 0;
6547  const string& db_name = m_Args[index]->GetString();
6548  const string kPrefix = "StructuredCommentPrefix";
6549  const string kSuffix = "StructuredCommentSuffix";
6550  const string& existing_text_option = m_Args[++index]->GetString();
6551  string delimiter;
6552  bool remove_field = false;
6553  x_GetOptionalArgs(delimiter, remove_field, index);
6554  edit::EExistingText existing_text = NMacroUtil::ActionTypeToExistingTextOption(existing_text_option, delimiter);
6555 
6556  if (!db_name.empty()) {
6558  if (bioseq) {
6560  if (existing_text == edit::eExistingText_add_qual) {
6561  if (x_MakeNewStructuredComment(db_name, kPrefix, kSuffix)) {
6562  m_DataIter->SetModified();
6563  }
6564  }
6565  else {
6566  bool found_user = false;
6567  for (CSeqdesc_CI desc_it(m_DataIter->GetBioseqHandle(), CSeqdesc::e_User); desc_it; ++desc_it) {
6568  if (CComment_rule::IsStructuredComment(desc_it->GetUser())) {
6569  CRef<CSeqdesc> new_seqdesc(new CSeqdesc());
6570  new_seqdesc->Assign(*desc_it);
6571  m_QualsChangedCount += s_UpdateStructCommentDb(*new_seqdesc, kPrefix, db_name, existing_text);
6572  m_QualsChangedCount += s_UpdateStructCommentDb(*new_seqdesc, kSuffix, db_name, existing_text);
6573 
6574  if (m_QualsChangedCount) {
6575  found_user = true;
6576  CRef<CCmdChangeSeqdesc> ecmd(new CCmdChangeSeqdesc(desc_it.GetSeq_entry_Handle(), *desc_it, *new_seqdesc));
6577  cmd.Reset(new CCmdComposite("Update structured comment"));
6578  cmd->AddCommand(*ecmd);
6579  m_DataIter->RunCommand(cmd, m_CmdComposite);
6580  }
6581  }
6582  }
6583  if (!found_user) {
6584  if (x_MakeNewStructuredComment(db_name, kPrefix, kSuffix)) {
6585  m_DataIter->SetModified();
6586  }
6587  }
6588  }
6589  }
6590  else if (user) {
6591  CObjectInfo oi = m_DataIter->GetEditedObject();
6593  m_QualsChangedCount += s_UpdateStructCommentDb(*user_object, kPrefix, db_name, existing_text);
6594  m_QualsChangedCount += s_UpdateStructCommentDb(*user_object, kSuffix, db_name, existing_text);
6595  m_DataIter->SetModified();
6596  }
6597  if (m_QualsChangedCount) {
6598  log << m_DataIter->GetBestDescr() << ": applied structured comment database name '" << db_name << "'";
6599  }
6600  x_LogFunction(log);
6601  }
6602  else if (remove_field) {
6603  if (user) {
6604  CObjectInfo oi = m_DataIter->GetEditedObject();
6606  if (user_object) {
6607  if (user_object->HasField(kPrefix) && user_object->RemoveNamedField(kPrefix)) {
6608  m_QualsChangedCount++;
6609  m_DataIter->SetModified();
6610  }
6611  if (user_object->HasField(kSuffix) && user_object->RemoveNamedField(kSuffix)) {
6612  m_QualsChangedCount++;
6613  m_DataIter->SetModified();
6614  }
6615  }
6616  }
6617  else if (bioseq) {
6618  CMQueryNodeValue::TObs res_oi = m_Args[0]->GetObjects();
6619  if (res_oi.empty() || existing_text == edit::eExistingText_leave_old) {
6620  return;
6621  }
6622 
6624  for (CSeqdesc_CI desc_it(m_DataIter->GetBioseqHandle(), CSeqdesc::e_User); desc_it; ++desc_it) {
6625  if (CComment_rule::IsStructuredComment(desc_it->GetUser())) {
6626  CRef<CSeqdesc> new_seqdesc(new CSeqdesc());
6627  new_seqdesc->Assign(*desc_it);
6628  if (new_seqdesc->GetUser().HasField(kPrefix) && new_seqdesc->SetUser().RemoveNamedField(kPrefix))
6629  m_QualsChangedCount++;
6630  if (new_seqdesc->GetUser().HasField(kSuffix) && new_seqdesc->SetUser().RemoveNamedField(kSuffix))
6631  m_QualsChangedCount++;
6632 
6633  if (m_QualsChangedCount) {
6634  CRef<CCmdChangeSeqdesc> ecmd(new CCmdChangeSeqdesc(desc_it.GetSeq_entry_Handle(), *desc_it, *new_seqdesc));
6635  cmd.Reset(new CCmdComposite("Update structured comment"));
6636  cmd->AddCommand(*ecmd);
6637  m_DataIter->RunCommand(cmd, m_CmdComposite);
6638  }
6639  }
6640  }
6641  }
6642 
6643  if (m_QualsChangedCount) {
6645  log << m_DataIter->GetBestDescr() << ": removed " << m_QualsChangedCount << " structured comment fields";
6646  x_LogFunction(log);
6647  }
6648  }
6649 }
6650 
6651 bool CMacroFunction_SetStructCommDb::x_MakeNewStructuredComment(const string& db_name, const string& kPrefix, const string& kSuffix)
6652 {
6653  CRef<CSeqdesc> seqdesc(new CSeqdesc());
6654  CRef<CUser_object> user_obj(new CUser_object);
6656  user_obj->AddField(kPrefix, CComment_rule::MakePrefixFromRoot(db_name));
6657  user_obj->AddField(kSuffix, CComment_rule::MakeSuffixFromRoot(db_name));
6658  seqdesc->SetUser(*user_obj);
6659 
6660  CObjectInfo oi = m_DataIter->GetEditedObject();
6662  if (!edit_bseq) return false;
6663 
6664  auto& descriptors = edit_bseq->SetDescr().Set();
6665  descriptors.push_back(seqdesc);
6667 
6668  CObjectInfo desc_oi(seqdesc, seqdesc->GetThisTypeInfo());
6670  objs.push_back(CMQueryNodeValue::SResolvedField(oi, desc_oi));
6671  m_Result->SetObjects(objs);
6672 
6673  return true;
6674 }
6675 
6677 {
6678  if (m_Args.size() < 2 || m_Args.size() > 4)
6679  return false;
6680 
6681  NMacroUtil::GetPrimitiveFromRef(m_Args[0].GetNCObject());
6682  if (!m_Args[0]->IsString() || !m_Args[1]->IsString()) {
6683  return false;
6684  }
6685  size_t index = 2;
6686  if (m_Args.size() > 2 && (!m_Args[index]->IsString() && !m_Args[index]->IsBool()))
6687  return false;
6688  if (m_Args.size() > 3 && !m_Args[++index]->IsBool())
6689  return false;
6690 
6691  return true;
6692 }
6693 
6694 int CMacroFunction_SetStructCommDb::s_UpdateStructCommentDb(CSeqdesc& seqdesc, const string& field, const string& db_name, edit::EExistingText existing_text)
6695 {
6696  if (!seqdesc.IsUser()) {
6697  return 0;
6698  }
6699 
6700  return s_UpdateStructCommentDb(seqdesc.SetUser(), field, db_name, existing_text);
6701 }
6702 
6703 int CMacroFunction_SetStructCommDb::s_UpdateStructCommentDb(CUser_object& user, const string& field, const string& db_name, edit::EExistingText existing_text)
6704 {
6705  int count = 0;
6706  bool field_is_prefix = NStr::EndsWith(field, "Prefix") ? true : false;
6707  string root = (field_is_prefix) ? CComment_rule::MakePrefixFromRoot(db_name) : CComment_rule::MakeSuffixFromRoot(db_name);
6708 
6709  if (user.HasField(field)) {
6710  CUser_field& user_field = user.SetField(field);
6711  if (user_field.IsSetData()) {
6712  if (user_field.GetData().IsStr()) {
6713  string orig_val = user_field.GetData().GetStr();
6715  if (AddValueToString(orig_val, db_name, existing_text)) {
6716  orig_val = (field_is_prefix) ? CComment_rule::MakePrefixFromRoot(orig_val) : CComment_rule::MakeSuffixFromRoot(orig_val);
6717  user_field.SetData().SetStr(orig_val);
6718  count++;
6719  }
6720  }
6721  else if (user_field.GetData().Which() == CUser_field::TData::e_not_set) {
6722  user_field.SetData().SetStr(root);
6723  count++;
6724  }
6725  }
6726  }
6727  else {
6728  user.AddField(field, root);
6729  count++;
6730  }
6731  return count;
6732 }
6733 
6735 {
6736  if (!user_object.IsSetData()) return;
6737  auto& user_fields = user_object.SetData();
6738 
6739  for (CUser_object::TData::iterator it = user_fields.begin(); it != user_fields.end(); ++it) {
6740  CUser_field& field = it->GetNCObject();
6741  if (field.IsSetLabel() && field.GetLabel().IsStr()) {
6742  if (NStr::Equal(field.GetLabel().GetStr(), "StructuredCommentSuffix") && it != user_fields.end() - 1) {
6743  swap(*it, *(user_fields.end() - 1));
6744  break;
6745  }
6746  }
6747  }
6748 }
6749 
6750 ///////////////////////////////////////////////////////////////////////////////
6751 /// class CMacroFunction_ValueFromTable
6752 /// ValueFromTable(table_name, col_number(integer))
6753 /// col_number - starts from 1
6754 ///
6755 DEFINE_MACRO_FUNCNAME(CMacroFunction_ValueFromTable, "ValueFromTable");
6756 void CMacroFunction_ValueFromTable::TheFunction()
6757 {
6758  const string& table_name = m_Args[0]->GetString();
6759  int col = (int)m_Args[1]->GetInt();
6760  if (col <= 0) {
6761  NCBI_THROW(CException, eUnknown, "The third argument (column number) should be at least 1");
6762  }
6763 
6764  m_Result->SetNotSet();
6765  if (NStr::EqualCase(m_DataIter->GetTableName(), table_name)) {
6766  string value = m_DataIter->GetValueFromTable(col - 1);
6767  m_Result->SetString(value);
6768  }
6769 }
6770 
6771 bool CMacroFunction_ValueFromTable::x_ValidArguments() const
6772 {
6773  if (m_Args.size() != 2)
6774  return false;
6775 
6776  return (m_Args[0]->IsString() && m_Args[1]->IsInt());
6777 }
6778 
6779 
6780 ///////////////////////////////////////////////////////////////////////////////
6781 /// CMacroFunction_GeneQual
6782 /// GeneQual(gene_field_name);
6783 ///
6784 DEFINE_MACRO_FUNCNAME(CMacroFunction_GeneQual, "GeneQual");
6785 void CMacroFunction_GeneQual::TheFunction()
6786 {
6787  CConstRef<CObject> object = m_DataIter->GetScopedObject().object;
6788  const CSeq_feat* cfeat = dynamic_cast<const CSeq_feat*>(object.GetPointer());
6789  if (!cfeat)
6790  return;
6791 
6792  CObjectInfo oi = m_DataIter->GetEditedObject();
6793  string field_name = m_Args[0]->GetString();
6794  const bool is_locustag = NMacroUtil::StringsAreEquivalent(field_name, "locus_tag");
6795 
6796 
6797  if (cfeat->IsSetData() && cfeat->GetData().IsGene()) {
6798  if (!NStr::StartsWith(field_name, "data.gene.")) {
6799  field_name = "data.gene." + field_name;
6800  }
6801  if (is_locustag) {
6802  NStr::ReplaceInPlace(field_name, "_", "-");
6803  }
6804  ResolveIdentToObjects(oi, field_name, *m_Result);
6805  }
6806  else {
6808  _ASSERT(feat);
6809  bool found_qual = false;
6810  if (feat->IsSetQual()) { // locus_tag
6811  CMQueryNodeValue tmp_result;
6812  ResolveIdentToObjects(oi, "qual", tmp_result);
6813  if (tmp_result.GetDataType() == CMQueryNodeValue::eNotSet) {
6814  return;
6815  }
6816  else {
6817  m_Result->SetDataType(CMQueryNodeValue::eObjects);
6818  if (is_locustag) {
6819  NStr::ReplaceInPlace(field_name, "-", "_");
6820  }
6821  for (auto&& it : tmp_result.SetObjects()) {
6822  CObjectInfo qual_oi = it.field;
6823  auto type_oi = qual_oi.FindClassMember("qual").GetMember();
6824  if (NStr::EqualNocase(type_oi.GetPrimitiveValueString(), field_name)) {
6825  m_Result->SetObjects().push_back(it);
6826  found_qual = true;
6827  }
6828  }
6829  }
6830  }
6831  if (!found_qual && feat->IsSetXref()) { // locus-tag
6832  CGene_ref* gene_xref = nullptr;
6833  for (auto&& it : feat->SetXref()) {
6834  if (it->IsSetData() && it->GetData().IsGene()) {
6835  gene_xref = &(it->SetData().SetGene());
6836  break;
6837  }
6838  }
6839  if (gene_xref) {
6840  if (is_locustag)
6841  NStr::ReplaceInPlace(field_name, "_", "-");
6842  CObjectInfo gene_oi(gene_xref, gene_xref->GetThisTypeInfo());
6843  ResolveIdentToObjects(gene_oi, field_name, *m_Result);
6844  }
6845  }
6846  }
6847  if (m_Result->GetDataType() == CMQueryNodeValue::eObjects &&
6848  m_Result->GetObjects().empty()) {
6849  m_Result->SetNotSet();
6850  }
6851 }
6852 
6853 bool CMacroFunction_GeneQual::x_ValidArguments() const
6854 {
6855  return (m_Args.size() == 1 && m_Args[0]->GetDataType() == CMQueryNodeValue::eString);
6856 }
6857 
6858 
6859 ///////////////////////////////////////////////////////////////////////////////
6860 /// class CMacroFunction_ApplyStrucVoucherPart
6861 /// ApplyStructVoucherPart(obj/voucher_type, part_name, newValue, existing_text, delimiter, remove_blank)
6862 /// Empty new values don't have any effect by default. If remove_blank is True,
6863 /// the existing field is removed.
6864 /// The last two parameters are optional
6865 
6868 {
6869  CConstRef<CObject> obj = m_DataIter->GetScopedObject().object;
6870  const CBioSource* cbsrc = dynamic_cast<const CBioSource*>(obj.GetPointer());
6871  if (!cbsrc)
6872  return;
6873 
6874  size_t index = 1;
6875  string voucher_type;
6876  string voucher_part = m_Args[index]->GetString();
6877  string newValue = NMacroUtil::GetStringValue(m_Args[++index]);
6878  const string& action_type = m_Args[++index]->GetString();
6879  string delimiter;
6880  bool remove_field = false;
6881  x_GetOptionalArgs(delimiter, remove_field, index);
6882 
6883  CObjectInfo oi = m_DataIter->GetEditedObject();
6885 
6886  if (m_Args[0]->IsString()) {
6887  voucher_type = m_Args[0]->GetString();
6888  }
6889  else if (m_Args[0]->AreObjects()) {
6890  objs = m_Args[0]->GetObjects();
6891  }
6892  else if (m_Args[0]->IsRef()) {
6893  x_GetObjectsFromRef(objs, 0);
6894  }
6895 
6896  if (voucher_type.empty() && objs.empty()) {
6897  return;
6898  }
6899  auto part = NMacroUtil::GetSVPartFromString(voucher_part);
6900  if (part == NMacroUtil::eSV_Error)
6901  NCBI_THROW(CException, eUnknown, " Unrecognized name of structured voucher part: " + voucher_part);
6902 
6903 
6906  if (!voucher_type.empty()) {
6907  auto subtype = COrgMod::GetSubtypeValue(voucher_type);
6908  if (subtype != COrgMod::eSubtype_bio_material &&
6911  NCBI_THROW(CException, eUnknown, "Invalid voucher type specified: " + voucher_type);
6912 
6913  if (!newValue.empty()) {
6914  if (existing_text != edit::eExistingText_add_qual) {
6915  bool has_voucher = false;
6916  EDIT_EACH_ORGMOD_ON_BIOSOURCE(mod_it, *bsrc) {
6917  auto orgmod = *mod_it;
6918  if (orgmod->IsSetSubtype() && orgmod->GetSubtype() == subtype) {
6919  x_ApplyPart(*orgmod, part, newValue, existing_text);
6920  has_voucher = true;
6921  }
6922  }
6923 
6924  if (!has_voucher) {
6925  auto new_mod = x_AddNewQual(subtype, part, newValue);
6926  bsrc->SetOrg().SetOrgname().SetMod().push_back(new_mod);
6927  m_QualsChangedCount++;
6928  }
6929  }
6930  else {
6931  auto new_mod = x_AddNewQual(subtype, part, newValue);
6932  bsrc->SetOrg().SetOrgname().SetMod().push_back(new_mod);
6933  m_QualsChangedCount++;
6934  }
6935  }
6936  else if (remove_field) {
6937  EDIT_EACH_ORGMOD_ON_BIOSOURCE(mod_it, *bsrc) {
6938  auto orgmod = *mod_it;
6939  if (orgmod->IsSetSubtype() && orgmod->GetSubtype() == subtype) {
6940  x_RemovePart(*orgmod, part);
6941  m_QualsChangedCount++;
6942  if (orgmod->GetSubname().empty())
6943  ERASE_ORGMOD_ON_BIOSOURCE(mod_it, *bsrc);
6944  }
6945  }
6946  if (bsrc->GetOrg().GetOrgname().GetMod().empty()) {
6947  bsrc->SetOrg().SetOrgname().ResetMod();
6948  }
6949  }
6950  }
6951  else {
6952  for (auto&& it : objs) {
6953  CObjectInfo res_oi = it.field;
6954  _ASSERT(res_oi.GetTypeFamily() == eTypeFamilyClass);
6955 
6957  if (!mod) continue;
6958 
6959  if (!newValue.empty()) {
6960  if (existing_text != edit::eExistingText_add_qual) {
6961  x_ApplyPart(*mod, part, newValue, existing_text);
6962  }
6963  else {
6964  auto new_mod = x_AddNewQual(mod->GetSubtype(), part, newValue);
6965  bsrc->SetOrg().SetOrgname().SetMod().push_back(new_mod);
6966  m_QualsChangedCount++;
6967  }
6968  }
6969  else if (remove_field) {
6970  x_RemovePart(*mod, part);
6971  if (mod->GetSubname().empty() && RemoveFieldByName(it)) {
6972  m_QualsChangedCount++;
6973  }
6974  }
6975  }
6976  }
6977 
6978 
6979  if (m_QualsChangedCount) {
6980  m_DataIter->SetModified();
6981 
6982  TChangedQuals report;
6983  if (!newValue.empty()) {
6984  report["setting new value to structured voucher " + voucher_part] = m_QualsChangedCount;
6985  }
6986  else if (remove_field) {
6987  report["removal of structured voucher " + voucher_part] = m_QualsChangedCount;
6988  }
6989  CRef<IFunctionLog> fnc_log(new CGeneralFuncLog(report));
6990  x_LogChangedQuals(fnc_log);
6991  }
6992 }
6993 
6995 {
6996  // 4 - delimiter (optional)
6997  // 5 - remove blank (optional)
6998  auto arg_nr = m_Args.size();
6999  if (arg_nr < 4 || arg_nr > 6)
7000  return false;
7001 
7002  bool first_ok = m_Args[0]->IsString() || m_Args[0]->AreObjects() || m_Args[0]->IsRef();
7003  if (!first_ok) return false;
7004 
7005  if (!m_Args[1]->IsString()) return false;
7006 
7007  NMacroUtil::GetPrimitiveFromRef(m_Args[2].GetNCObject());
7008  bool third_ok = m_Args[2]->IsString() || m_Args[2]->IsInt() || m_Args[2]->IsDouble();
7009  if (!third_ok) return false;
7010 
7011  if (!m_Args[3]->IsString()) return false;
7012 
7013  if (arg_nr > 4 && (!m_Args[4]->IsString() && !m_Args[4]->IsBool())) return false;
7014 
7015  if (arg_nr > 5 && !m_Args[5]->IsBool()) return false;
7016 
7017  return true;
7018 }
7019 
7021  COrgMod& orgmod, NMacroUtil::EStructVoucherPart part,
7022  const string& newValue, edit::EExistingText existing_text)
7023 {
7024  string orig_inst, orig_coll, orig_id;
7025  if (orgmod.IsSetSubname()) {
7026  COrgMod::ParseStructuredVoucher(orgmod.GetSubname(), orig_inst, orig_coll, orig_id);
7027  }
7028 
7029  auto update = [&newValue, existing_text, this](string& value, const string& orig_value)
7030  {
7031  edit::AddValueToString(value, newValue, existing_text);
7032  if (!NStr::EqualCase(orig_value, value))
7034  };
7035 
7036  string inst{ orig_inst }, coll{ orig_coll }, id{ orig_id };
7037  switch (part) {
7038  case NMacroUtil::eSV_Inst: update(inst, orig_inst); break;
7039  case NMacroUtil::eSV_Coll: update(coll, orig_coll); break;
7040  case NMacroUtil::eSV_Specid: update(id, orig_id); break;
7041  default: break;
7042  }
7043 
7044  orgmod.SetSubname(COrgMod::MakeStructuredVoucher(inst, coll, id));
7045 }
7046 
7048 {
7049  string inst, coll, id;
7050  if (orgmod.IsSetSubname()) {
7051  COrgMod::ParseStructuredVoucher(orgmod.GetSubname(), inst, coll, id);
7052  }
7053 
7054  switch (part) {
7055  case NMacroUtil::eSV_Inst: inst.clear(); break;
7056  case NMacroUtil::eSV_Coll: coll.clear(); break;
7057  case NMacroUtil::eSV_Specid: id.clear(); break;
7058  default: break;
7059  }
7060 
7061  orgmod.SetSubname(COrgMod::MakeStructuredVoucher(inst, coll, id));
7062 }
7063 
7065 {
7066  CRef<COrgMod> new_mod(new COrgMod);
7067  new_mod->SetSubtype(subtype);
7068  string inst, coll, id;
7069  switch (part) {
7070  case NMacroUtil::eSV_Inst: inst = newValue; break;
7071  case NMacroUtil::eSV_Coll: coll = newValue; break;
7072  case NMacroUtil::eSV_Specid: id = newValue; break;
7073  default: break;
7074  }
7075  new_mod->SetSubname(COrgMod::MakeStructuredVoucher(inst, coll, id));
7076  return new_mod;
7077 }
7078 
7079 ///////////////////////////////////////////////////////////////////////////////
7080 /// class CMacroFunction_SetAutodefOption
7081 /// SetAutodefOption(autodefopt_field, new_value, existing_text, delimiter)
7082 /// The last parameter is optional
7083 DEFINE_MACRO_FUNCNAME(CMacroFunction_SetAutodefOption, "SetAutodefOption")
7084 void CMacroFunction_SetAutodefOption::TheFunction()
7085 {
7086  CConstRef<CObject> object = m_DataIter->GetScopedObject().object;
7087  const CUser_object* user = dynamic_cast<const CUser_object*>(object.GetPointer());
7088  if (!(user && user->IsAutodefOptions())) {
7089  return;
7090  }
7091 
7092  size_t index = 0;
7093  string field_name = m_Args[index]->GetString();
7094  NStr::TruncateSpacesInPlace(field_name);
7095  const string& field_value = m_Args[++index]->GetString();
7096  const string& existing_text_option = m_Args[++index]->GetString();
7097  string delimiter;
7098  bool remove_field = false;
7099  x_GetOptionalArgs(delimiter, remove_field, index);
7100 
7101  edit::EExistingText existing_text = NMacroUtil::ActionTypeToExistingTextOption(existing_text_option, delimiter);
7102 
7103  CObjectInfo oi = m_DataIter->GetEditedObject();
7105  if (existing_text == edit::eExistingText_add_qual) {
7106  // add a new field to the AutodefOptions
7107  user_object->AddField(field_name, field_value);
7108  m_QualsChangedCount++;
7109  }
7110  else {
7111  if (user_object->HasField(field_name)) {
7112  CUser_field& user_field = user_object->SetField(field_name);
7113  if (user_field.IsSetData() && user_field.GetData().IsStr()) {
7114  string orig_val = user_field.GetData().GetStr();
7115  if (AddValueToString(orig_val, field_value, existing_text)) {
7116  user_field.SetData().SetStr(orig_val);
7117  m_QualsChangedCount++;
7118  }
7119  }
7120  }
7121  else {
7122  // add a new field to the AutodefOptions
7123  user_object->AddField(field_name, field_value);
7124  m_QualsChangedCount++;
7125  }
7126  }
7127 
7128  if (m_QualsChangedCount) {
7129  m_DataIter->SetModified();
7131  log << m_DataIter->GetBestDescr() << ": applied ('" << field_name << "', '" << field_value << "') field-value pair";
7132  x_LogFunction(log);
7133  }
7134 
7135 }
7136 
7137 bool CMacroFunction_SetAutodefOption::x_ValidArguments() const
7138 {
7139  if (m_Args.size() < 3 || m_Args.size() > 4)
7140  return false;
7141 
7142  for (size_t i = 0; i < m_Args.size(); ++i) {
7143  if (!m_Args[i]->IsString()) {
7144  return false;
7145  }
7146  }
7147  return true;
7148 }
7149 
7150 
7151 END_SCOPE(macro)
7153 
7154 /* @} */
User-defined methods of the data storage class.
User-defined methods of the data storage class.
User-defined methods of the data storage class.
#define static
@ eExtreme_Biological
5' and 3'
Definition: Na_strand.hpp:62
bool IsSetOrgMod(void) const
Definition: BioSource.cpp:415
bool IsSetOrgname(void) const
Definition: BioSource.cpp:405
CBioseq_Handle –.
bool IsNa(void) const
Definition: Bioseq.cpp:345
bool IsAa(void) const
Definition: Bioseq.cpp:350
static bool CleanupUserObject(CUser_object &object)
static string MakeSuffixFromRoot(const string &root)
static string MakePrefixFromRoot(const string &root)
static void NormalizePrefix(string &prefix)
static bool IsStructuredComment(const CUser_object &user)
Definition: Dbtag.hpp:53
CFeat_CI –.
Definition: feat_ci.hpp:64
bool IsEmpty(void) const
Definition: GB_block.cpp:55
@Gb_qual.hpp User-defined methods of the data storage class.
Definition: Gb_qual.hpp:61
static int CodonToIndex(char base1, char base2, char base3)
bool IsSuppressed(void) const
Definition: Gene_ref.cpp:75
Subclass of the IQueryParseUserObject which is held as the user-defined object in each CQueryParseNod...
Definition: macro_exec.hpp:71
class CMacroExecException
Definition: macro_ex.hpp:196
@Name_std.hpp User-defined methods of the data storage class.
Definition: Name_std.hpp:56
CObjectInfoEI –.
Definition: objectiter.hpp:125
CObjectInfoMI –.
Definition: objectiter.hpp:432
CObjectInfo –.
Definition: objectinfo.hpp:597
@OrgMod.hpp User-defined methods of the data storage class.
Definition: OrgMod.hpp:54
@ eVocabulary_insdc
Definition: OrgMod.hpp:69
static bool IsValidSubtypeName(const string &str, EVocabulary vocabulary=eVocabulary_raw)
Definition: OrgMod.cpp:86
static TSubtype GetSubtypeValue(const string &str, EVocabulary vocabulary=eVocabulary_raw)
Definition: OrgMod.cpp:62
static string MakeStructuredVoucher(const string &inst, const string &coll, const string &id)
Definition: OrgMod.cpp:540
static bool ParseStructuredVoucher(const string &str, string &inst, string &coll, string &id)
Definition: OrgMod.cpp:188
@RNA_ref.hpp User-defined methods of the data storage class.
Definition: RNA_ref.hpp:54
string GetRnaProductName(void) const
Definition: RNA_ref.cpp:145
void SetRnaProductName(const string &product, string &remainder)
Definition: RNA_ref.cpp:225
CRegexpUtil –.
Definition: regexp.hpp:312
CScope –.
Definition: scope.hpp:92
ESubtype GetSubtype(void) const
CSeq_entry_Handle –.
CSeq_feat_Handle –.
namespace ncbi::objects::
Definition: Seq_feat.hpp:58
const string & GetNamedQual(const CTempString &qual_name) const
Return a named qualifier.
Definition: Seq_feat.cpp:429
void AddQualifier(const string &qual_name, const string &qual_val)
Add a qualifier to this feature.
Definition: Seq_feat.cpp:291
const CGene_ref * GetGeneXref(void) const
See related function in util/feature.hpp.
Definition: Seq_feat.cpp:181
CSeqdesc_CI –.
Definition: seqdesc_ci.hpp:65
static TSubtype GetSubtypeValue(const string &str, EVocabulary vocabulary=eVocabulary_raw)
Definition: SubSource.cpp:128
static bool IsValidSubtypeName(const string &str, EVocabulary vocabulary=eVocabulary_raw)
Definition: SubSource.cpp:157
@ eVocabulary_insdc
Definition: SubSource.hpp:83
CUser_field & SetValue(int value)
set a data field to a given value Int8 and TGi values can be stored into 'str' field if the value doe...
Definition: User_field.hpp:283
void SetObjectType(EObjectType obj_type)
void AddUnverifiedOrganism()
void AddUnverifiedContaminant()
bool RemoveNamedField(const string &field_name, NStr::ECase ecase=NStr::eCase)
@ eObjectType_StructuredComment
bool HasField(const string &str, const string &delim=".", NStr::ECase use_case=NStr::eCase) const
Verify that a named field exists.
bool IsAutodefOptions() const
CUser_object & AddField(const string &label, const string &value, EParseField parse=eParse_String)
add a data field to the user object that holds a given value
void AddUnverifiedMisassembled()
CUser_field & SetField(const string &str, const string &delim=".", const string &obj_subtype=kEmptyStr, NStr::ECase use_case=NStr::eCase)
Access a named field in this user object.
EObjectType GetObjectType() const
void AddUnverifiedFeature()
Definition: set.hpp:45
static auto & FixCapitalizationInString
static const string kSatelliteTypes[]
static CS_COMMAND * cmd
Definition: ct_dynamic.c:26
static void cleanup(void)
Definition: ct_dynamic.c:30
#define true
Definition: bool.h:35
static DLIST_TYPE *DLIST_NAME() first(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:46
static const char table_name[]
Definition: bcp.c:249
static int type
Definition: getdata.c:31
static const char * str(char *buf, int n)
Definition: stats.c:84
static char tmp[3200]
Definition: utf8.c:42
static const char location[]
Definition: config.c:97
Utility macros and typedefs for exploring NCBI objects from general.asn.
#define EDIT_EACH_USERFIELD_ON_USEROBJECT(Itr, Var)
#define ERASE_USERFIELD_ON_USEROBJECT(Itr, Var)
ERASE_USERFIELD_ON_USEROBJECT.
const TResidue codons[4][4]
Definition: gnomon_seq.cpp:76
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
void swap(NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair1, NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair2)
Definition: ncbimisc.hpp:1508
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
const CMemberId & GetId(void) const
const string & GetName(void) const
objects::ECapChange ConvertStringtoCapitalOption(const string &cap_name)
Definition: macro_util.cpp:105
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
virtual bool x_ChangeFields(CObjectInfo &src, CObjectInfo &dest)
virtual void TheFunction()
class CMacroFunction_EditStringQual Usage: EditStringQual(field_name|rt_obj, find_text,...
bool StringsAreEquivalent(const string &name1, const string &name2)
Definition: macro_util.cpp:397
bool RemoveFirstName(objects::CName_std &std_name)
static bool s_EditText(string &str, const string &find, const string &repl, ESearchLoc loc, bool case_sensitive, bool is_regex=false)
bool SetQualStringValue(CObjectInfo &oi, const string &value)
Functions make the action and collect statistics.
void CleanupForTaxnameChange(CObjectInfo oi)
Definition: macro_util.cpp:526
void SetString(const string &data)
Set/get underlying data type.
Definition: macro_exec.hpp:125
void x_RemovePart(objects::COrgMod &orgmod, NMacroUtil::EStructVoucherPart part)
static void s_MoveSuffixToTheEnd(objects::CUser_object &user_object)
virtual void TheFunction()
Function implementation.
static bool s_IsATGC(char ch)
CMacroFunction_SetCodonsRecognized SetCodonsRecognized(field_name) The field_name specifies one of th...
virtual bool x_ValidArguments() const
Tests the number and the type of function arguments.
void x_SetOrCreateDestFeatFields(const objects::CSeq_feat &src_feat, CMQueryNodeValue::TObs &result, size_t index)
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
objects::CSeqFeatData::ESubtype GetFeatSubtype(const string &feat_type)
Definition: macro_util.cpp:350
void x_SetFields(CMQueryNodeValue::TObs &objs, const string &newValue, objects::edit::EExistingText existing_text, vector< string > &new_values)
static void s_ResetModSubsrcQuals(CBioSource &bsrc)
static bool s_AddSrcSubSource(objects::CBioSource &bsrc, int subtype, const string &value)
const char * kMobileElementTType
Definition: macro_util.cpp:938
static string s_GetMobileElemTType(const string &value)
static vector< string > ParseDegenerateCodons(string codon)
bool x_GetSourceFields(CObjectInfo oi, size_t index, CMQueryNodeValue::TObs &result)
virtual bool x_ChangeFields(CObjectInfo &src, CObjectInfo &dest)=0
virtual void TheFunction()
Function implementation.
static bool s_SetEnumValue(CObjectInfo &obj, const string &str)
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
bool x_GetSpecialField(const string &field, CMQueryNodeValue::TObs &objs, objects::CScope &scope)
CMQueryNodeValue::EType GetPrimitiveFromRef(CMQueryNodeValue &node)
Definition: macro_util.cpp:274
void x_SetNewPrimitiveValue(CObjectInfo &oi, const string &newValue, objects::edit::EExistingText existing_text, vector< string > &new_values)
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
bool AreObjects() const
Definition: macro_exec.hpp:152
static void s_AddNewDBlinkValue(CUser_field &user_field, const string &newValue)
AddDBLink(dblink_type, newValue, existing_text, delimiter, remove_blank) The last parameter is option...
static string s_GetMobileElemTName(const string &value)
virtual void TheFunction()
class CMacroFunction_ConvertStringQual ConvertStringQual(src_field, dst_field, capitalization,...
bool ResolveAndSetSimpleTypeValue(CObjectInfo &oi, const string &field_name, const CMQueryNodeValue &value, objects::edit::EExistingText existing_text=objects::edit::eExistingText_replace_old)
Resolve dot qualified ASN.1 node_name using the object information instance provided as a parameter (...
bool RemoveFieldByName(CMQueryNodeValue::SResolvedField &res_field)
Remove the object information instance corresponding to field, using information about its parent nod...
list< SResolvedField > TObs
Definition: macro_exec.hpp:92
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
virtual void TheFunction()
Function implementation.
static string s_GetEnumValue(CObjectInfo &obj)
bool GetSimpleTypeValue(CObjectInfo &oi, const string &field_name, CMQueryNodeValue &value)
Get single node data from the node specified by parameter of type CObjectInfo and additionally field ...
virtual void TheFunction()
class CMacroFunction_SetStringQual Expected Syntax: SetStringQual(field_name, newValue,...
bool x_CheckArguments(size_t index) const
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
void Dereference()
If it is a reference it is resolved to the first non reference type in the hierarchy.
Definition: macro_exec.cpp:94
const TObs & GetObjects() const
Definition: macro_exec.hpp:144
virtual bool x_ValidArguments() const
Tests the number and the type of function arguments.
bool x_SetFields(CObjectInfo oi, CMQueryNodeValue::TObs &result, size_t index)
void GetPrimitiveObjInfosWithContainers(CMQueryNodeValue::TObs &objs, const CMQueryNodeValue::SResolvedField &info)
Definition: macro_util.cpp:252
bool ResolveIdentToObjects(const CObjectInfo &oi, const string &identifier, CMQueryNodeValue &v)
Resolve name to the list of objects.
static void s_SetFeatField(CRef< CSeq_feat > feat, CObjectInfo &oi, const string &field_name, CMQueryNodeValue::TObs &result)
const char * kStrCommFieldValue
Definition: macro_util.cpp:940
bool SetSimpleTypeValue(CObjectInfo &oi, const CMQueryNodeValue &value, objects::edit::EExistingText existing_text=objects::edit::eExistingText_replace_old)
Set single node data to the node specified by parameter of type CObjectInfo.
static const string s_GetExpansion(const string &ch)
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
CConstRef< objects::CSeq_feat > m_ConstDestFeat
void RemoveGeneXref(objects::CSeq_feat &feat)
void ChangeFields(CMQueryNodeValue::TObs &src_objs, CMQueryNodeValue::TObs &dest_objs)
void SetDataType(EType dt)
Definition: macro_exec.hpp:121
bool x_MakeNewStructuredComment(const string &db_name, const string &kPrefix, const string &kSuffix)
string GetStringValue(CRef< CMQueryNodeValue > &value)
converts ints and doubles into string, by changing the type of the value
Definition: macro_util.cpp:330
bool IsString() const
Definition: macro_exec.hpp:146
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
void x_AddBioSrcModifier(const string &subtype, const string &newValue)
void x_ParseFields(CMQueryNodeValue::TObs &dest_objs, const string &text_portion, objects::edit::EExistingText existing_text)
string x_GetSourceString(CObjectInfo &src)
static bool s_AddNewUserField(CRef< CSeqdesc > &user_object_desc, const string &dblink, const string &newValue)
const char * kSatelliteType
Definition: macro_util.cpp:935
const char * kSatelliteName
Definition: macro_util.cpp:936
virtual bool x_ValidArguments() const
Tests the number and the type of function arguments.
void x_RmvOutsideFields(CMQueryNodeValue::TObs &resolved_objs, const CRemoveTextOptions &options)
CObjectInfo GetPrimitiveObjInfo(const CObjectInfo &info)
Definition: macro_util.cpp:199
bool IsNotSet() const
Definition: macro_exec.hpp:153
bool x_GetDestFields(CObjectInfo oi, size_t index, CMQueryNodeValue::TObs &result)
const string & GetString() const
Definition: macro_exec.hpp:139
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
EType GetDataType() const
Definition: macro_exec.hpp:122
CRef< CRemoveTextOptions > x_GetRemoveTextOptions(size_t start_index) const
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
CRef< objects::CSeq_feat > m_EditDestFeat
const char * kStrCommFieldName
Definition: macro_util.cpp:942
bool x_DoFieldsExist(CObjectInfo oi, CMQueryNodeValue::TObs &result, size_t index)
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
void GetPrimitiveObjectInfos(CMQueryNodeValue::TObs &objs, const CMQueryNodeValue::SResolvedField &info)
Definition: macro_util.cpp:212
virtual void TheFunction()
class CMacroFunction_ConvertStringQual ConvertStringQual(src_field, dst_field, capitalization,...
EStructVoucherPart GetSVPartFromString(const string voucher_part)
Definition: macro_util.cpp:815
virtual bool x_ValidArguments() const
Tests the number and the type of function arguments.
virtual void TheFunction()
Function implementation.
static string s_MakeSatellite(const string &type, const string &name)
Int4 m_QualsChangedCount
Number of changed qualifiers during the function call.
bool GetFieldsByName(CMQueryNodeValue::TObs *results, const CObjectInfo &oi_i, const string &field_name)
Resolve existing dot qualified ASN.1 name (field_name) starting from the object information instance ...
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
bool x_DoDestFeatFieldsExist(const objects::CSeq_feat &src_feat, CMQueryNodeValue::TObs &result, const string &dest_feattype, const string &dest_field)
bool IsTaxname(CMQueryNodeValue::SResolvedField &res)
Definition: macro_util.cpp:513
virtual bool x_ValidArguments() const
Tests the number and the type of function arguments.
virtual void TheFunction()
class CMacroFunction_CopyStringQual Expected syntax: CopyStringQual( src_field, dest_field,...
CRef< objects::edit::CParseTextOptions > x_GetParseOptions(size_t start_index)
static string s_GetSatelliteName(const string &value)
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
static const string kAmbiguities
static int s_AddGBQualifier(objects::CSeq_feat &feat, const string &qual_name, const string &newValue)
static void s_SetVectorValue(CUser_field &user_field, const string &newValue, const string &del)
virtual void TheFunction()
Function implementation.
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
CRef< objects::COrgMod > x_AddNewQual(objects::COrgMod::TSubtype subtype, NMacroUtil::EStructVoucherPart part, const string &newValue)
bool ResolveIdentToSimple(const CObjectInfo &oi, const string &identifier, CMQueryNodeValue &v)
Resolve name to simple types value.
bool SetFieldsByName(CMQueryNodeValue::TObs *results, CObjectInfo &oi_i, const string &field_name)
Resolve not necessarily existing dot qualified ASN.1 name (field_name) starting from the object infor...
void x_CopyFields(CMQueryNodeValue::TObs &src_objs, CMQueryNodeValue::TObs &dest_objs)
virtual void TheFunction()
Function implementation.
static string s_GatherExistingValues(CUser_field &user_field, const string &newValue, const string &del)
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
void x_GetObjectsFromRef(CMQueryNodeValue::TObs &objects, const size_t &index)
objects::edit::EExistingText ActionTypeToExistingTextOption(const string &action_type, const string &delimiter)
Definition: macro_util.cpp:64
CRef< CMQueryNodeValue > m_Result
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
static Int4 s_RemoveFields(CIRef< IMacroBioDataIter > &dataiter, CMQueryNodeValue::TObs &objs)
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
void x_SetFieldType(const string &strcomm_field)
bool IsSatelliteSubfield(const string &field)
Definition: macro_util.cpp:903
static int s_UpdateStructCommentDb(objects::CSeqdesc &seqdesc, const string &field, const string &db_name, objects::edit::EExistingText existing_text)
objects::ECapChange m_CapChange
static ESearchLoc s_GetLocFromName(const string &name)
bool IsMobileElementTSubfield(const string &field)
Definition: macro_util.cpp:908
const char * kMobileElementTQual
Definition: macro_util.cpp:937
static string s_MakeMobileElementT(const string &type, const string &name)
virtual void TheFunction()
class CMacroFunction_CopyStringQual Expected syntax: CopyStringQual( src_field, dest_field,...
static const string kReplacements[]
bool x_SwapFields(CObjectInfo &src, CObjectInfo &dest)
static void s_AddUnverifiedType(CUser_object &user, NMacroUtil::EUnverifiedType type)
class CMacroFunction_AddUnverified AddUnverified("Features"); The user object will be added only to n...
string x_GetSourceString(CObjectInfo &src)
void x_LogFunction(CNcbiOstrstream &logstr)
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
bool ApplyFirstName(objects::CName_std &std_name, const string &newValue, objects::edit::EExistingText existing_text)
virtual bool x_ValidArguments() const
Tests the number and the type of function arguments.
bool IsBiosourceModifier(const string &field)
Definition: macro_util.cpp:505
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
virtual bool x_ChangeFields(CObjectInfo &src, CObjectInfo &dest)
static void s_SetBioSourceField(CRef< CBioSource > bsrc, CObjectInfo &oi, const string &field_name, CMQueryNodeValue::TObs &dest_objs)
bool EditText(string &str) const
Definition: macro_util.cpp:946
virtual bool x_ValidArguments() const
Tests the number and the type of function arguments.
CRef< objects::CSeq_feat > m_CreatedFeat
void x_SetField(CConstRef< CObject > &obj, const string &fieldname, CMQueryNodeValue::TObs &result)
void SwapGbQualWithValues(CMQueryNodeValue::TObs &objs)
Definition: macro_util.cpp:282
void SetObjects(const TObs &obs)
Definition: macro_exec.hpp:131
static const char * sm_FunctionName
EditRelatedFeatureQual(feat_type, field_name, find_text, repl_text, location, case_sensitive,...
virtual bool x_ValidArguments() const
Tests the number and the type of function arguments.
string x_GetSourceString(CObjectInfo &src)
const char * kMobileElementTName
Definition: macro_util.cpp:939
DEFINE_MACRO_FUNCNAME(CMacroFunction_CopyFeatQual, "CopyFeatureQual")
CopyFeatureQual(src_field, dest_feature_type, dest_feature_field, update_mrna, existing_text_opt,...
virtual bool x_ChangeFields(CObjectInfo &src, CObjectInfo &dest)
void x_ApplyPart(objects::COrgMod &orgmod, NMacroUtil::EStructVoucherPart part, const string &newValue, objects::edit::EExistingText existing_text)
static bool s_AddSrcOrgMod(objects::CBioSource &bsrc, int subtype, const string &value)
EUnverifiedType GetUnverifiedType(const string &value)
Definition: macro_util.cpp:913
virtual bool x_ValidArguments() const
Tests the number and the type of function arguments.
CIRef< IMacroBioDataIter > m_DataIter
static bool s_SwapFields(CObjectInfo &src, CObjectInfo &dest)
vector< CConstRef< objects::CSeq_feat > > TVecFeatList
Definition: macro_util.hpp:58
virtual bool x_ValidArguments(void) const
Tests the number and the type of function arguments.
vector< pair< objects::CSeqdesc_CI, CRef< objects::CSeqdesc > > > m_ChangedDescriptors
virtual void TheFunction()
Function implementation.
objects::edit::EExistingText m_ExistingText
void RemoveEmptyDescriptors(objects::CBioseq &bseq)
const char * kStrCommDbname
Definition: macro_util.cpp:941
virtual bool x_ValidArguments() const
Tests the number and the type of function arguments.
void x_EditFields(CMQueryNodeValue::TObs &resolved_objs, const string &find_txt, const string &repl_txt, ESearchLoc loc, bool case_sensitive, bool is_regex)
static string s_GetSatelliteType(const string &value)
@ eUnVer_Misassembled
Definition: macro_util.hpp:136
@ eUnVer_Contaminant
Definition: macro_util.hpp:137
@ eUnknown
Definition: app_popup.hpp:72
size_t TMemberIndex
Type used for indexing class members and choice variants.
Definition: serialdef.hpp:230
virtual void Assign(const CSerialObject &source, ESerialRecursionMode how=eRecursive)
Set object to copy of another one.
virtual const CTypeInfo * GetThisTypeInfo(void) const =0
static const TObjectType * SafeCast(TTypeInfo type)
Definition: serialutil.hpp:76
@ ePrimitiveValueString
string|char*|const char*
Definition: serialdef.hpp:153
@ ePrimitiveValueInteger
(signed|unsigned) (char|short|int|long)
Definition: serialdef.hpp:151
@ ePrimitiveValueChar
char
Definition: serialdef.hpp:150
@ ePrimitiveValueBool
bool
Definition: serialdef.hpp:149
@ ePrimitiveValueEnum
enum
Definition: serialdef.hpp:154
@ ePrimitiveValueReal
float|double
Definition: serialdef.hpp:152
@ eTypeFamilyClass
Definition: serialdef.hpp:140
@ eTypeFamilyContainer
Definition: serialdef.hpp:142
@ eTypeFamilyPointer
Definition: serialdef.hpp:143
@ eTypeFamilyPrimitive
Definition: serialdef.hpp:139
@ fMerge_SingleRange
Definition: Seq_loc.hpp:332
CElementIterator BeginElements(void) const
Create container elements iterator.
CObjectInfo AddNewPointedElement(void) const
add new pointer element, create new pointed object and return it
Definition: objectinfo.cpp:329
CObjectInfo GetPointedObject(void) const
Get data and type information of object to which this type refers.
Definition: objectinfo.cpp:102
bool GetPrimitiveValueBool(void) const
Get boolean data.
Definition: objectinfo.cpp:144
const CMemberInfo * GetMemberInfo(void) const
TObjectPtr GetObjectPtr(void) const
Get pointer to object.
CObjectInfo GetMember(void) const
Get class member data.
void SetPrimitiveValueString(const string &value)
Definition: objectinfo.cpp:282
void SetPrimitiveValueBool(bool value)
Set boolean data.
Definition: objectinfo.cpp:227
int GetPrimitiveValueInt(void) const
Get data as int.
Definition: objectinfo.cpp:154
void SetPrimitiveValueInt8(Int8 value)
Definition: objectinfo.cpp:247
void SetPrimitiveValueInt4(Int4 value)
Definition: objectinfo.cpp:237
CObjectInfo AddNewElement(void) const
Add and return new element object.
Definition: objectinfo.cpp:321
CMemberIterator GetClassMemberIterator(TMemberIndex index) const
Create class member iterator that initially points to specified member.
ETypeFamily GetTypeFamily(void) const
Get data type family.
void GetPrimitiveValueString(string &value) const
Get string data.
Definition: objectinfo.cpp:199
double GetPrimitiveValueDouble(void) const
Get data as double.
Definition: objectinfo.cpp:194
CMemberIterator FindClassMember(const string &memberName) const
Find class member by its name.
Int4 GetPrimitiveValueInt4(void) const
Get data as Int4.
Definition: objectinfo.cpp:174
void SetPrimitiveValueDouble(double value)
Definition: objectinfo.cpp:277
const string & GetName(void) const
Get type name.
Definition: objectinfo.hpp:106
void Erase(void)
void SetPrimitiveValueInt(int value)
Definition: objectinfo.cpp:257
EPrimitiveValueType GetPrimitiveValueType(void) const
Get type of primitive value.
Definition: objectinfo.cpp:109
Int8 GetPrimitiveValueInt8(void) const
Get data as Int8.
Definition: objectinfo.cpp:184
bool IsSet(void) const
Is member assigned a value.
CObjectTypeInfo GetElementType(void) const
Get type information of an element of container.
Definition: objectinfo.cpp:85
void GetCdssForGene(const CMappedFeat &gene_feat, list< CMappedFeat > &cds_feats, CFeatTree *feat_tree=0, const SAnnotSelector *base_sel=0)
Definition: feature.cpp:3409
CMappedFeat GetBestMrnaForCds(const CMappedFeat &cds_feat, CFeatTree *feat_tree=0, const SAnnotSelector *base_sel=0)
Definition: feature.cpp:3341
CMappedFeat GetBestCdsForMrna(const CMappedFeat &mrna_feat, CFeatTree *feat_tree=0, const SAnnotSelector *base_sel=0)
Definition: feature.cpp:3360
CRef< CSeq_loc > Seq_loc_Merge(const CSeq_loc &loc, CSeq_loc::TOpFlags flags, CScope *scope)
Merge ranges in the seq-loc.
const CSeq_feat * GetCDSForProduct(const CBioseq &product, CScope *scope)
Get the encoding CDS feature of a given protein sequence.
Definition: sequence.cpp:2549
CBioseq_Handle GetBioseqHandle(const CSeq_id &id)
Get bioseq handle by seq-id.
Definition: scope.cpp:95
CSeq_feat_Handle GetSeq_featHandle(const CSeq_feat &feat, EMissing action=eMissing_Default)
Definition: scope.cpp:200
CConstRef< CBioseq > GetCompleteBioseq(void) const
Get the complete bioseq.
bool IsAa(void) const
CSeq_entry_Handle GetSeq_entry_Handle(void) const
Get parent Seq-entry handle.
virtual const CSeq_loc & GetProduct(void) const
bool IsSetProduct(void) const
virtual const CSeq_loc & GetLocation(void) const
CConstRef< CSeq_feat > GetOriginalSeq_feat(void) const
CSeq_entry_Handle GetSeq_entry_Handle(void) const
Definition: seqdesc_ci.cpp:326
TObjectType * GetPointer(void) const THROWS_NONE
Get pointer,.
Definition: ncbiobj.hpp:1684
TObjectType * GetNCPointer(void) const THROWS_NONE
Get pointer,.
Definition: ncbiobj.hpp:1174
CConstRef< C > ConstRef(const C *object)
Template function for conversion of const object pointer to CConstRef.
Definition: ncbiobj.hpp:2024
CRef< C > Ref(C *object)
Helper functions to get CRef<> and CConstRef<> objects.
Definition: ncbiobj.hpp:2015
TObjectType * GetPointer(void) THROWS_NONE
Get pointer,.
Definition: ncbiobj.hpp:998
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:1439
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:773
bool IsNull(void) const THROWS_NONE
Check if pointer is null – same effect as Empty().
Definition: ncbiobj.hpp:735
TObjectType & GetObject(void) const
Get object.
Definition: ncbiobj.hpp:1697
int32_t Int4
4-byte (32-bit) signed integer
Definition: ncbitype.h:102
int64_t Int8
8-byte (64-bit) signed integer
Definition: ncbitype.h:104
size_t Replace(CTempStringEx search, CTempString replace, CRegexp::TCompile compile_flags=CRegexp::fCompile_default, CRegexp::TMatch match_flags=CRegexp::fMatch_default, size_t max_replace=0)
Replace occurrences of a substring within a string by pattern.
Definition: regexp.cpp:289
unsigned int TCompile
Type definitions used for code clarity.
Definition: regexp.hpp:76
string GetResult(void)
Get result string.
Definition: regexp.hpp:582
@ fCompile_default
Definition: regexp.hpp:102
@ fCompile_ignore_case
Definition: regexp.hpp:103
@ fMatch_default
Definition: regexp.hpp:127
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define USING_SCOPE(ns)
Use the specified namespace.
Definition: ncbistl.hpp:78
#define END_SCOPE(ns)
End the previously defined scope.
Definition: ncbistl.hpp:75
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
#define BEGIN_SCOPE(ns)
Define a new scope.
Definition: ncbistl.hpp:72
NCBI_NS_STD::string::size_type SIZE_TYPE
Definition: ncbistr.hpp:132
static string Int8ToString(Int8 value, TNumToStringFlags flags=0, int base=10)
Convert Int8 to string.
Definition: ncbistr.hpp:5159
static string DoubleToString(double value, int precision=-1, TNumToStringFlags flags=0)
Convert double to string.
Definition: ncbistr.hpp:5187
#define kEmptyStr
Definition: ncbistr.hpp:123
static Int8 StringToInt8(const CTempString str, TStringToNumFlags flags=0, int base=10)
Convert string to Int8.
Definition: ncbistr.cpp:793
static list< string > & Split(const CTempString str, const CTempString delim, list< string > &arr, TSplitFlags flags=0, vector< SIZE_TYPE > *token_pos=NULL)
Split a string using specified delimiters.
Definition: ncbistr.cpp:3461
static SIZE_TYPE FindNoCase(const CTempString str, const CTempString pattern, SIZE_TYPE start, SIZE_TYPE end, EOccurrence which=eFirst)
Find the pattern in the specified range of a string using a case insensitive search.
Definition: ncbistr.cpp:2993
static bool EndsWith(const CTempString str, const CTempString end, ECase use_case=eCase)
Check if a string ends with a specified suffix value.
Definition: ncbistr.hpp:5430
static bool IsBlank(const CTempString str, SIZE_TYPE pos=0)
Check if a string is blank (has no text).
Definition: ncbistr.cpp:106
#define NPOS
Definition: ncbistr.hpp:133
static const string BoolToString(bool value)
Convert bool to string.
Definition: ncbistr.cpp:2815
static void TruncateSpacesInPlace(string &str, ETrunc where=eTrunc_Both)
Truncate spaces in a string (in-place)
Definition: ncbistr.cpp:3201
static string IntToString(int value, TNumToStringFlags flags=0, int base=10)
Convert int to string.
Definition: ncbistr.hpp:5084
static SIZE_TYPE Find(const CTempString str, const CTempString pattern, ECase use_case=eCase, EDirection direction=eForwardSearch, SIZE_TYPE occurrence=0)
Find the pattern in the string.
Definition: ncbistr.cpp:2891
static bool EqualCase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-sensitive equality of a substring with another string.
Definition: ncbistr.hpp:5325
static SIZE_TYPE FindCase(const CTempString str, const CTempString pattern, SIZE_TYPE start, SIZE_TYPE end, EOccurrence which=eFirst)
Find the pattern in the specified range of a string using a case sensitive search.
Definition: ncbistr.hpp:5490
static long StringToLong(const CTempString str, TStringToNumFlags flags=0, int base=10)
Convert string to long.
Definition: ncbistr.cpp:653
static bool StartsWith(const CTempString str, const CTempString start, ECase use_case=eCase)
Check if a string starts with a specified prefix value.
Definition: ncbistr.hpp:5412
static bool EqualNocase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-insensitive equality of a substring with another string.
Definition: ncbistr.hpp:5353
static enable_if< is_arithmetic< TNumeric >::value||is_convertible< TNumeric, Int8 >::value, string >::type NumericToString(TNumeric value, TNumToStringFlags flags=0, int base=10)
Convert numeric value to string.
Definition: ncbistr.hpp:673
static bool Equal(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2, ECase use_case=eCase)
Test for equality of a substring with another string.
Definition: ncbistr.hpp:5384
static string & ReplaceInPlace(string &src, const string &search, const string &replace, SIZE_TYPE start_pos=0, SIZE_TYPE max_replace=0, SIZE_TYPE *num_replace=0)
Replace occurrences of a substring within a string.
Definition: ncbistr.cpp:3405
static string & ToUpper(string &str)
Convert string to upper case – string& version.
Definition: ncbistr.cpp:424
@ fConvErr_NoThrow
Do not throw an exception on error.
Definition: ncbistr.hpp:285
@ eNocase
Case insensitive compare.
Definition: ncbistr.hpp:1206
@ eCase
Case sensitive compare.
Definition: ncbistr.hpp:1205
const TSubtype & GetSubtype(void) const
Get the Subtype member data.
Definition: BioSource_.hpp:539
void SetSubtype(TSubtype value)
Assign a value to Subtype data member.
Definition: SubSource_.hpp:319
bool IsSetOrg(void) const
Check if a value has been assigned to Org data member.
Definition: BioSource_.hpp:497
bool IsSetSubtype(void) const
Check if a value has been assigned to Subtype data member.
Definition: BioSource_.hpp:527
const TOrg & GetOrg(void) const
Get the Org member data.
Definition: BioSource_.hpp:509
void SetOrg(TOrg &value)
Assign a value to Org data member.
Definition: BioSource_.cpp:108
void SetName(const TName &value)
Assign a value to Name data member.
Definition: SubSource_.hpp:359
TSubtype & SetSubtype(void)
Assign a value to Subtype data member.
Definition: BioSource_.hpp:545
void ResetSubtype(void)
Reset Subtype data member.
Definition: BioSource_.cpp:113
const TStr & GetStr(void) const
Get the variant data.
bool IsSetData(void) const
the object itself Check if a value has been assigned to Data data member.
bool IsStr(void) const
Check if variant Str is selected.
Definition: Object_id_.hpp:291
bool IsStrs(void) const
Check if variant Strs is selected.
const TStrs & GetStrs(void) const
Get the variant data.
const TData & GetData(void) const
Get the Data member data.
bool IsStr(void) const
Check if variant Str is selected.
bool IsSetLabel(void) const
field label Check if a value has been assigned to Label data member.
TData & SetData(void)
Assign a value to Data data member.
void SetNum(TNum value)
Assign a value to Num data member.
const TStr & GetStr(void) const
Get the variant data.
Definition: Object_id_.hpp:297
void SetLabel(TLabel &value)
Assign a value to Label data member.
const TData & GetData(void) const
Get the Data member data.
void SetType(TType &value)
Assign a value to Type data member.
void ResetNum(void)
Reset Num data member.
void SetData(TData &value)
Assign a value to Data data member.
const TLabel & GetLabel(void) const
Get the Label member data.
const TType & GetType(void) const
Get the Type member data.
bool IsSetData(void) const
Check if a value has been assigned to Data data member.
E_Choice Which(void) const
Which variant is currently selected.
@ e_not_set
No variant selected.
const TMod & GetMod(void) const
Get the Mod member data.
Definition: OrgName_.hpp:839
bool IsSetDb(void) const
ids in taxonomic or culture dbases Check if a value has been assigned to Db data member.
Definition: Org_ref_.hpp:479
const TSubname & GetSubname(void) const
Get the Subname member data.
Definition: OrgMod_.hpp:347
void SetSubtype(TSubtype value)
Assign a value to Subtype data member.
Definition: OrgMod_.hpp:316
const TDb & GetDb(void) const
Get the Db member data.
Definition: Org_ref_.hpp:491
bool IsSetSubname(void) const
Check if a value has been assigned to Subname data member.
Definition: OrgMod_.hpp:335
TMod & SetMod(void)
Assign a value to Mod data member.
Definition: OrgName_.hpp:845
void SetSubname(const TSubname &value)
Assign a value to Subname data member.
Definition: OrgMod_.hpp:356
const TOrgname & GetOrgname(void) const
Get the Orgname member data.
Definition: Org_ref_.hpp:541
@ eSubtype_specimen_voucher
Definition: OrgMod_.hpp:106
@ eSubtype_bio_material
Definition: OrgMod_.hpp:119
@ eSubtype_culture_collection
Definition: OrgMod_.hpp:118
const TName & GetName(void) const
Get the Name member data.
Definition: Prot_ref_.hpp:378
TType GetType(void) const
Get the Type member data.
Definition: RNA_ref_.hpp:529
bool IsSetType(void) const
Check if a value has been assigned to Type data member.
Definition: RNA_ref_.hpp:510
TXref & SetXref(void)
Assign a value to Xref data member.
Definition: Seq_feat_.hpp:1314
bool IsSetComment(void) const
Check if a value has been assigned to Comment data member.
Definition: Seq_feat_.hpp:1037
bool IsSetData(void) const
the specific data Check if a value has been assigned to Data data member.
Definition: Seq_feat_.hpp:913
bool IsSetQual(void) const
qualifiers Check if a value has been assigned to Qual data member.
Definition: Seq_feat_.hpp:1135
bool IsProt(void) const
Check if variant Prot is selected.
bool IsCdregion(void) const
Check if variant Cdregion is selected.
void SetComment(const TComment &value)
Assign a value to Comment data member.
Definition: Seq_feat_.hpp:1058
bool IsSetXref(void) const
cite other relevant features Check if a value has been assigned to Xref data member.
Definition: Seq_feat_.hpp:1296
const TLocation & GetLocation(void) const
Get the Location member data.
Definition: Seq_feat_.hpp:1117
bool IsGene(void) const
Check if variant Gene is selected.
const TData & GetData(void) const
Get the Data member data.
Definition: Seq_feat_.hpp:925
void SetData(TData &value)
Assign a value to Data data member.
Definition: Seq_feat_.cpp:94
const TProduct & GetProduct(void) const
Get the Product member data.
Definition: Seq_feat_.hpp:1096
const TProt & GetProt(void) const
Get the variant data.
const TXref & GetXref(void) const
Get the Xref member data.
Definition: Seq_feat_.hpp:1308
vector< CRef< CSeqFeatXref > > TXref
Definition: Seq_feat_.hpp:122
void ResetXref(void)
Reset Xref data member.
Definition: Seq_feat_.cpp:182
const TRna & GetRna(void) const
Get the variant data.
TQual & SetQual(void)
Assign a value to Qual data member.
Definition: Seq_feat_.hpp:1153
bool IsSetProduct(void) const
product of process Check if a value has been assigned to Product data member.
Definition: Seq_feat_.hpp:1084
bool IsRna(void) const
Check if variant Rna is selected.
bool IsSetLocation(void) const
feature made from Check if a value has been assigned to Location data member.
Definition: Seq_feat_.hpp:1105
bool IsGenbank(void) const
Check if variant Genbank is selected.
Definition: Seqdesc_.hpp:1090
const TUser & GetUser(void) const
Get the variant data.
Definition: Seqdesc_.cpp:384
const TTitle & GetTitle(void) const
Get the variant data.
Definition: Seqdesc_.hpp:1032
const TGenbank & GetGenbank(void) const
Get the variant data.
Definition: Seqdesc_.cpp:334
void SetDescr(TDescr &value)
Assign a value to Descr data member.
Definition: Bioseq_.cpp:65
TUser & SetUser(void)
Select the variant.
Definition: Seqdesc_.cpp:390
bool IsUser(void) const
Check if variant User is selected.
Definition: Seqdesc_.hpp:1122
@ e_User
user defined object
Definition: Seqdesc_.hpp:124
@ e_Title
a title for this sequence
Definition: Seqdesc_.hpp:115
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
static string kPrefix
Definition: id2info.cpp:146
int i
Macro exceptions.
Functions that resolve field names described in asn format.
const string kSuffix
const struct ncbi::grid::netcache::search::fields::CREATED created
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
const char * tag
Int mod(Int i, Int j)
Definition: njn_integer.hpp:67
vector< CConstRef< CSeq_feat > > GetRelatedFeatures(const CSeq_feat &obj_feat, CSeqFeatData::ESubtype constraint_type, CRef< CScope > scope)
static const char delimiter[]
Utility macros and typedefs for exploring NCBI objects from seqfeat.asn.
#define ERASE_ORGMOD_ON_BIOSOURCE(Itr, Var)
ERASE_ORGMOD_ON_BIOSOURCE.
#define EDIT_EACH_ORGMOD_ON_BIOSOURCE(Itr, Var)
#define EDIT_EACH_SUBSOURCE_ON_BIOSOURCE(Itr, Var)
#define EDIT_EACH_GBQUAL_ON_SEQFEAT(Itr, Var)
EExistingText
@ eExistingText_append_semi
@ eExistingText_add_qual
@ eExistingText_leave_old
@ eExistingText_replace_old
bool AddValueToString(string &str, const string &value, EExistingText existing_text)
Add text to an existing string, using the "existing_text" directive to combine new text with existing...
Definition: type.c:6
#define _ASSERT
else result
Definition: token2.c:20
C++ wrappers for the Perl-compatible regular expression (PCRE) library.
CRef< CCmdComposite > UpdatemRNAProduct(const objects::CSeq_feat &protein, objects::CScope &scope, string &message)
void SetProteinFeature(objects::CSeq_feat &prot, objects::CBioseq_Handle product, const objects::CSeq_feat &cds)
#define const
Definition: zconf.h:232
Modified on Tue Apr 23 07:37:26 2024 by modify_doxy.py rev. 669887