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

Go to the SVN repository for this file.

1 /* $Id: update_align.cpp 47479 2023-05-02 13:24:02Z ucko $
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: Igor Filippov
27  */
28 
29 
30 #include <ncbi_pch.hpp>
33 #include <util/line_reader.hpp>
34 #include <objmgr/bioseq_ci.hpp>
35 
38 
45 
48 
49 #include <wx/filedlg.h>
50 #include <wx/choicdlg.h>
51 #include <wx/msgdlg.h>
52 
55 
56 void CUpdateAlign::apply(CSeq_entry_Handle tse, ICommandProccessor* cmdProcessor, wxWindow *parent)
57 {
58  wxFileDialog file(parent, wxT("Import file"), wxEmptyString, wxEmptyString,
59  CFileExtensions::GetDialogFilter(CFileExtensions::kAllFiles), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
60  if (file.ShowModal() != wxID_OK) {
61  return;
62  }
63 
64  m_FilePath = file.GetPath();
65  CTextAlignParams params;
66  params.SetUnknown(wxT("?Nn"));
67  params.SetMatch(wxT(":"));
68  params.SetBegin(wxT("-.Nn?"));
69  params.SetMiddle(wxT("-.")); // for interpreting gaps
70  params.SetEnd(wxT("-.Nn?"));
71  params.SetSeqType(1);
72 
74  dlg.SetData(params);
75  if (dlg.ShowModal() == wxID_OK) {
76  params = dlg.GetData();
77  x_ReadAlign(params);
78 
79  if (m_SeqAlign) {
81  if (x_ProcessNotPresentIDs(parent)) {
82  CRef<CSeq_annot> new_annot(new CSeq_annot);
83  new_annot->SetData().SetAlign().push_back(m_SeqAlign);
85  cmdProcessor->Execute(cmd);
86  }
87  }
88  }
89 }
90 
92 {
93  m_NonPresentIDs.clear();
94  _ASSERT(m_NonPresentIDs.empty());
95 
96  for (size_t index = 0; index < m_Ids.size(); ++index) {
97  CRef<CSeq_id> id1;
98  try {
99  id1.Reset(new CSeq_id(m_Ids[index], CSeq_id::fParse_Default));
100  } catch (exception &) {
101  id1.Reset();
102  }
103 
104  bool found = false;
105  if (id1) {
106  for (CBioseq_CI bi(tse); bi && !found; ++bi) {
107  for (auto&& id_it : bi->GetId()) {
108  CConstRef<CSeq_id> id2 = id_it.GetSeqId();
109  if (id2 && id1->Match(*id2)) {
110  found = true;
111  break;
112  }
113  }
114 
115  }
116  }
117  if (!found) {
118  m_NonPresentIDs.emplace_back(m_Ids[index], (int)index);
119  }
120  }
121 }
122 
123  // TODO ask user if not-present id should be a far pointer, deleted, etc.
124 /*
125  "This is a far pointer"// id = "acc"+id;
126  "Remove this sequence from the alignment"
127  "Use this ID for this sequence"
128 */
130 {
131  if (m_NonPresentIDs.empty()) return true;
132 
133  wxArrayString choices;
134  choices.Add(_("All unmatched sequences are far pointers"));
135  choices.Add(_("Remove all unmatched sequences from the alignment"));
136  choices.Add(_("Read in a file that maps alignment IDs to sequence IDs"));
137 
138  wxString msg;
139  msg << "Unable to find " << m_NonPresentIDs.size() << " sequence";
140  if (m_NonPresentIDs.size() > 1) {
141  msg << "s";
142  }
143  msg << " from alignment in set";
144 
145  int answer = wxGetSingleChoiceIndex(msg, _("Unmatched sequences found"), choices);
146  if (answer == 0) {
148  }
149  else if (answer == 1) {
151  }
152  else if (answer == 2) {
153  x_MapNonPresentIDs(parent);
154  }
155 
156  return (answer != -1); // -1 corresponds to pressing the Cancel button
157 }
158 
159 namespace {
160 
161  struct SFind_ID
162  {
163  SFind_ID(const string& id_name) : m_IdName(id_name) {}
164 
165  bool operator() (const pair<string, string>& str_pair) const
166  {
167  return NStr::FindNoCase(str_pair.first, m_IdName) != NPOS;
168  }
169  private:
170  string m_IdName;
171  };
172 
173  CUpdateAlign::TIdToRowVec::iterator s_IsIDNonPresent(CUpdateAlign::TIdToRowVec& nonPresentIDs, int index)
174  {
175  for (CUpdateAlign::TIdToRowVec::iterator it = nonPresentIDs.begin();
176  it != nonPresentIDs.end(); ++it) {
177  if (it->second == index) {
178  return it;
179  }
180  }
181  return nonPresentIDs.end();
182  }
183 
184  string s_GetIDLabel(const string& initial_val)
185  {
186  string id_label = initial_val;
187  size_t pos = id_label.find("|");
188  if (pos != string::npos) {
189  id_label = id_label.substr(pos + 1, string::npos);
190  }
191  return id_label;
192  }
193 }
194 
196 {
198  if (!m_SeqAlign->IsSetSegs()
199  || !m_SeqAlign->GetSegs().IsDenseg()
200  || m_SeqAlign->GetDim() == 2) {
201  return;
202  }
203 
204  CDense_seg& dense_seg = m_SeqAlign->SetSegs().SetDenseg();
205  int dim = static_cast<int>(dense_seg.GetIds().size());
206 
207  vector<int> rows;
208  for (auto& it : m_NonPresentIDs) {
209  rows.push_back(it.second);
210  }
211 
212  if (dense_seg.IsSetNumseg()) {
213  CDense_seg::TNumseg numseg = dense_seg.GetNumseg();
214 
215  // remove rows from starts
216  if (dense_seg.IsSetStarts()) {
217  CDense_seg::TStarts new_starts;
218  auto starts_it = dense_seg.GetStarts().begin();
219 
220  for (int seg = 0; seg < numseg; ++seg) {
221  for (int index = 0; index < dim; ++index) {
222  if (find(rows.begin(), rows.end(), index) == rows.end()) {
223  new_starts.push_back(*starts_it);
224  }
225  ++starts_it;
226  }
227  }
228  dense_seg.SetStarts().swap(new_starts);
229  }
230 
231  // remove rows from strands
232  if (dense_seg.IsSetStrands()) {
233  CDense_seg::TStrands new_strands;
234  auto strand_it = dense_seg.GetStrands().begin();
235 
236  for (int seg = 0; seg < numseg; ++seg) {
237  for (int index = 0; index < dim; ++index) {
238  if (find(rows.begin(), rows.end(), index) == rows.end()) {
239  new_strands.push_back(*strand_it);
240  }
241  ++strand_it;
242  }
243  }
244  dense_seg.SetStrands().swap(new_strands);
245  }
246  }
247 
248  // remove ids that are not present
249  CDense_seg::TIds new_ids;
250  for (size_t index = 0; index < dense_seg.GetIds().size(); ++index) {
251  if (find(rows.begin(), rows.end(), (int)index) == rows.end()) {
252  new_ids.push_back(dense_seg.GetIds()[index]);
253  }
254  }
255 
256  dense_seg.SetDim(static_cast<CDense_seg::TDim>(new_ids.size()));
257  m_SeqAlign->SetDim(static_cast<CSeq_align::TDim>(new_ids.size()));
258  dense_seg.SetIds().swap(new_ids);
259  dense_seg.RemovePureGapSegs(); // sets numsegs correctly
260 }
261 
262 
264 {
266  _ASSERT(!m_NonPresentIDs.empty());
267 
268  if (!m_SeqAlign->IsSetSegs()
269  || !m_SeqAlign->GetSegs().IsDenseg()) {
270  return;
271  }
272 
273  CDense_seg& dense_seg = m_SeqAlign->SetSegs().SetDenseg();
274  size_t previous_ids = dense_seg.GetIds().size();
275 
276  CDense_seg::TIds new_ids;
277  for (size_t index = 0; index < dense_seg.GetIds().size(); ++index) {
278  bool found = false;
279  for (auto& it : m_NonPresentIDs) {
280  if ((int)index == it.second) {
281  string farptrID = "acc" + s_GetIDLabel(it.first);
282  CRef<CSeq_id> new_id(new CSeq_id(CSeq_id::e_Local, farptrID));
283  new_ids.push_back(new_id);
284  found = true;
285  break;
286  }
287  }
288 
289  if (!found) {
290  new_ids.push_back(dense_seg.GetIds()[index]);
291  }
292  }
293 
294  dense_seg.SetIds().swap(new_ids);
295  _ASSERT(previous_ids == dense_seg.GetIds().size());
296 }
297 
298 void CUpdateAlign::x_MapNonPresentIDs(wxWindow *parent)
299 {
301  _ASSERT(!m_NonPresentIDs.empty());
302 
303  if (!m_SeqAlign->IsSetSegs()
304  || !m_SeqAlign->GetSegs().IsDenseg()) {
305  return;
306  }
307 
308  vector<pair<string, string>> oldId_toNewId;
309  wxFileDialog file(parent, wxT("Import ID map from file"), wxEmptyString, wxEmptyString,
311  wxFD_OPEN | wxFD_FILE_MUST_EXIST);
312  if (file.ShowModal() != wxID_OK) {
313  return;
314  }
315 
316  wxString path = file.GetPath();
317  if (!path.IsEmpty()) {
318 
319  CNcbiIfstream istr(path.fn_str());
320  CStreamLineReader line_reader(istr);
321  do {
322  string str = *++line_reader;
324  if (str.empty())
325  continue;
326  list<string> row_values;
327  NStr::Split(str, "\t", row_values, NStr::fSplit_MergeDelimiters);
328  if (row_values.size() == 2) {
329  oldId_toNewId.emplace_back(*row_values.begin(), *row_values.rbegin());
330  }
331  } while (!line_reader.AtEOF());
332  }
333 
334  CDense_seg& dense_seg = m_SeqAlign->SetSegs().SetDenseg();
335  size_t previous_ids = dense_seg.GetIds().size();
336 
337  int unmapped = 0;
338  string unmapped_ids = "(";
339  CDense_seg::TIds new_ids;
340 
341  for (size_t index = 0; index < dense_seg.SetIds().size(); ++index) {
342  auto id_it = s_IsIDNonPresent(m_NonPresentIDs, (int)index);
343  if (id_it == m_NonPresentIDs.end()) {
344  new_ids.push_back(dense_seg.GetIds()[index]);
345  }
346  else {
347  std::function<bool(const pair<string, string>& str_pair)> tester = SFind_ID(id_it->first);
348  auto map_it = find_if(begin(oldId_toNewId), end(oldId_toNewId), tester);
349  if (map_it == oldId_toNewId.end()) {
350  unmapped++;
351  unmapped_ids += id_it->first;
352  unmapped_ids += ", ";
353  new_ids.push_back(dense_seg.GetIds()[index]);
354  }
355  else {
356  CRef<CSeq_id> new_id(new CSeq_id(CSeq_id::e_Local, s_GetIDLabel(map_it->second)));
357  new_ids.push_back(new_id);
358  m_NonPresentIDs.erase(id_it);
359  }
360  }
361  }
362  dense_seg.SetIds().swap(new_ids);
363 
364  if (unmapped > 0) {
365  unmapped_ids.pop_back();
366  unmapped_ids.pop_back();
367  unmapped_ids += ")";
368 
369  string msg = "Mapping not found for ";
370  msg += NStr::NumericToString(unmapped) + unmapped_ids;
371  msg += " sequence";
372  if (unmapped > 1) {
373  msg += "s";
374  }
375 
376  msg += "\n";
377  if (unmapped == 1) {
378  msg += "Is this a far pointer? ";
379  }
380  else {
381  msg += "Are these far pointers?";
382  }
383 
384  if (wxYES == wxMessageBox(ToWxString(msg), "Info", wxYES_DEFAULT|wxYES_NO, parent)) {
386  }
387  }
388 
389  _ASSERT(previous_ids == dense_seg.GetIds().size());
390 }
391 
392 /*
393 int CUpdateAlign::FindMostFrequentLength(const map<string,string> &id_to_seq)
394 {
395  map<int,int> lengths;
396  for (map<string, string>::const_iterator i = id_to_seq.begin(); i != id_to_seq.end(); ++i)
397  {
398  size_t length = i->second.length();
399  lengths[length]++;
400  }
401  int length = 0;
402  int max_occ = 0;
403  for (map<int,int>::iterator c = lengths.begin(); c != lengths.end(); ++c)
404  {
405  if (c->second > max_occ)
406  {
407  max_occ = c->second;
408  length = c->first;
409  }
410  }
411  return length;
412 }
413 
414 bool CUpdateAlign::ProcessDiffLengths(map<string,string> &id_to_seq, int length)
415 {
416  set<string> diff_length;
417  for (map<string, string>::const_iterator i = id_to_seq.begin(); i != id_to_seq.end(); ++i)
418  {
419  size_t length2 = i->second.length();
420  if (length2 != length)
421  diff_length.insert(i->first);
422  }
423 
424  if (!diff_length.empty())
425  {
426  wxString msg;
427  msg << "Remove " << diff_length.size() << " sequence";
428  if (diff_length.size() > 1)
429  msg << "s";
430  msg << " with different length";
431  if (diff_length.size() > 1)
432  msg << "s";
433  int answer = wxMessageBox (msg, _("Different length sequences detected"), wxYES_NO | wxICON_QUESTION);
434  if (answer == wxYES)
435  {
436  for (set<string>::const_iterator s = diff_length.begin(); s != diff_length.end(); ++s)
437  id_to_seq.erase(*s);
438  }
439  else
440  return true;
441  }
442  return false;
443 }
444 */
445 
446 static string s_FormatErrors(const CAlnReader::TErrorList& errors)
447 {
448  string errmsg = "";
449 
450  ITERATE(CAlnReader::TErrorList, iter2, errors) {
451  const string& id = (*iter2).GetID();
452  int line_num = (*iter2).GetLineNum();
453 
454  if (!NStr::IsBlank(errmsg)) {
455  errmsg += "\n";
456  }
457  if (line_num > -1) {
458  errmsg += "At line ";
459  errmsg += NStr::IntToString(line_num);
460  }
461  if (!NStr::IsBlank(id)) {
462  errmsg += "(Sequence ID ";
463  errmsg += id;
464  errmsg += ") ";
465  }
466  errmsg += (*iter2).GetMsg();
467  }
468  return errmsg;
469 }
470 
472 {
473  string unknown = ToStdString(params.GetUnknown());
474  string match = ToStdString(params.GetMatch());
475  string gapbegin = ToStdString(params.GetBegin());
476  string gapmiddle = ToStdString(params.GetMiddle());
477  string gapend = ToStdString(params.GetEnd());
478 
479  vector<CAlnReader::EAlphabet> alphas;
480  if (params.GetSeqType() == 1) {
481  alphas.push_back(CAlnReader::eAlpha_Nucleotide);
482  }
483  else if (params.GetSeqType() == 2) {
484  alphas.push_back(CAlnReader::eAlpha_Protein);
485  }
486  else {
487  alphas.push_back(CAlnReader::eAlpha_Nucleotide);
488  alphas.push_back(CAlnReader::eAlpha_Protein);
489  }
490 
492  string errmsg;
493 
494  ITERATE(vector<CAlnReader::EAlphabet>, iter, alphas) {
495  CAlnReader reader(file.GetIstream());
496  try {
497  reader.SetMissing(unknown);
498  reader.SetMatch(match);
499  reader.SetBeginningGap(gapbegin);
500  reader.SetMiddleGap(gapmiddle);
501  reader.SetEndGap(gapend);
502  reader.SetAlphabet(*iter);
503 
504  reader.Read();
505  m_SeqAlign = reader.GetSeqAlign();
506  m_Ids = reader.GetIds();
507  errmsg = s_FormatErrors(reader.GetErrorList());
508  break;
509  }
511  _TRACE("reading text alignment failed: " << e.what());
512  errmsg = s_FormatErrors(reader.GetErrorList());
513  NcbiMessageBox(errmsg);
514  }
515  }
516 }
517 
class CAlnReader supports importing a large variety of text-based alignment formats into standard dat...
Definition: aln_reader.hpp:100
const TErrorList & GetErrorList(void) const
Definition: aln_reader.hpp:234
void Read(bool guess, bool generate_local_ids=false, objects::ILineErrorListener *pErrorListener=nullptr)
void SetMatch(const string &value)
Definition: aln_reader.hpp:195
CRef< objects::CSeq_align > GetSeqAlign(TFastaFlags fasta_flags=0, objects::ILineErrorListener *pErrorListener=nullptr)
Create ASN.1 classes from the parsed alignment.
Definition: aln_reader.cpp:516
const vector< string > & GetIds(void) const
Parsed result data accessors.
Definition: aln_reader.hpp:225
void SetMiddleGap(const string &value)
Definition: aln_reader.hpp:399
void SetEndGap(const string &value)
Definition: aln_reader.hpp:412
void SetBeginningGap(const string &value)
Definition: aln_reader.hpp:385
void SetAlphabet(const string &value)
Definition: aln_reader.hpp:371
void SetMissing(const string &value)
Definition: aln_reader.hpp:192
CBioseq_CI –.
Definition: bioseq_ci.hpp:69
void RemovePureGapSegs()
Remove any segments in which every row has a gap (these can arise when ExtractRows is used)
Definition: Dense_seg.cpp:574
static wxString GetDialogFilter(EFileType fileType)
const CTextAlignParams & GetData() const
void SetData(const CTextAlignParams &data)
CSeq_entry_Handle –.
Simple implementation of ILineReader for i(o)streams.
void SetEnd(wxString value)
void SetMatch(wxString value)
void SetMiddle(wxString value)
wxString GetBegin() const
void SetSeqType(int value)
wxString GetUnknown() const
wxString GetMatch() const
void SetBegin(wxString value)
void SetUnknown(wxString value)
wxString GetMiddle() const
vector< pair< string, int > > TIdToRowVec
vector< string > m_Ids
bool x_ProcessNotPresentIDs(wxWindow *parent)
CRef< objects::CSeq_align > m_SeqAlign
void x_ReadAlign(const CTextAlignParams &params)
TIdToRowVec m_NonPresentIDs
void x_ChangeIDsToFarPointers()
void x_FindNotPresentIDs(objects::CSeq_entry_Handle tse)
void x_MapNonPresentIDs(wxWindow *parent)
void x_RemoveIDsFromAlign()
void apply(objects::CSeq_entry_Handle tse, ICommandProccessor *cmdProcessor, wxWindow *parent)
wxString m_FilePath
Undo/Redo interface for editing operations.
virtual void Execute(IEditCommand *command, wxWindow *window=0)=0
#define _(proto)
Definition: ct_nlmzip_i.h:78
static CS_COMMAND * cmd
Definition: ct_dynamic.c:26
#define bool
Definition: bool.h:34
static unsigned int line_num
Definition: attributes.c:11
static const char * str(char *buf, int n)
Definition: stats.c:84
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define NULL
Definition: ncbistd.hpp:225
#define _TRACE(message)
Definition: ncbidbg.hpp:122
#define _DEBUG_ARG(arg)
Definition: ncbidbg.hpp:134
EDialogReturnValue NcbiMessageBox(const string &message, TDialogType type=eDialog_Ok, EDialogIcon icon=eIcon_Exclamation, const string &title="Error", EDialogTextMode text_mode=eRaw)
Definition: message_box.cpp:48
bool AtEOF(void) const
Indicates (negatively) whether there is any more input.
bool Match(const CSeq_id &sid2) const
Match() - TRUE if SeqIds are equivalent.
Definition: Seq_id.hpp:1065
@ fParse_Default
By default in ParseIDs and IsValid, allow raw parsable non-numeric accessions and plausible local acc...
Definition: Seq_id.hpp:102
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:773
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
IO_PREFIX::ifstream CNcbiIfstream
Portable alias for ifstream.
Definition: ncbistre.hpp:439
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 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 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 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
@ fSplit_MergeDelimiters
Merge adjacent delimiters.
Definition: ncbistr.hpp:2498
bool IsSetNumseg(void) const
number of segments here Check if a value has been assigned to Numseg data member.
Definition: Dense_seg_.hpp:446
bool IsSetStrands(void) const
Check if a value has been assigned to Strands data member.
Definition: Dense_seg_.hpp:568
const TStarts & GetStarts(void) const
Get the Starts member data.
Definition: Dense_seg_.hpp:530
vector< ENa_strand > TStrands
Definition: Dense_seg_.hpp:109
vector< TSignedSeqPos > TStarts
Definition: Dense_seg_.hpp:107
void SetDim(TDim value)
Assign a value to Dim data member.
Definition: Dense_seg_.hpp:427
vector< CRef< CSeq_id > > TIds
Definition: Dense_seg_.hpp:106
TStarts & SetStarts(void)
Assign a value to Starts data member.
Definition: Dense_seg_.hpp:536
TStrands & SetStrands(void)
Assign a value to Strands data member.
Definition: Dense_seg_.hpp:586
bool IsSetStarts(void) const
start OFFSETS in ids order within segs Check if a value has been assigned to Starts data member.
Definition: Dense_seg_.hpp:518
const TIds & GetIds(void) const
Get the Ids member data.
Definition: Dense_seg_.hpp:505
TNumseg GetNumseg(void) const
Get the Numseg member data.
Definition: Dense_seg_.hpp:465
TIds & SetIds(void)
Assign a value to Ids data member.
Definition: Dense_seg_.hpp:511
const TStrands & GetStrands(void) const
Get the Strands member data.
Definition: Dense_seg_.hpp:580
@ e_Local
local use
Definition: Seq_id_.hpp:95
void SetData(TData &value)
Assign a value to Data data member.
Definition: Seq_annot_.cpp:244
FILE * file
Lightweight interface for getting lines of data with minimal memory copying.
#define wxT(x)
Definition: muParser.cpp:41
const struct ncbi::grid::netcache::search::fields::SIZE size
static int match(register const pcre_uchar *eptr, register const pcre_uchar *ecode, const pcre_uchar *mstart, int offset_top, match_data *md, eptrblock *eptrb, unsigned int rdepth)
Definition: pcre_exec.c:513
Utility macros and typedefs for exploring NCBI objects from seqset.asn.
#define _ASSERT
USING_SCOPE(objects)
static string s_FormatErrors(const CAlnReader::TErrorList &errors)
wxString ToWxString(const string &s)
Definition: wx_utils.hpp:173
string ToStdString(const wxString &s)
Definition: wx_utils.hpp:161
Modified on Wed Apr 17 13:09:16 2024 by modify_doxy.py rev. 669887