Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BrowseDialog.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
11 /* This is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This software is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public
22  * License along with this software. If not, see
23  * <http://www.gnu.org/licenses/>.
24  *
25  */
26 
27 #include "hugin/BrowseDialog.h"
28 #include "hugin/huginApp.h"
29 #include "wx/dir.h"
30 #include "wx/busyinfo.h"
32 #include "hugin/MainFrame.h"
33 #include "base_wx/wxcms.h"
34 #include "base_wx/LensTools.h"
35 #include "base_wx/platform.h"
36 
37 wxDECLARE_EVENT(wxEVT_COMMAND_THUMBNAILTHREAD_UPDATE, wxCommandEvent);
38 wxDEFINE_EVENT(wxEVT_COMMAND_THUMBNAILTHREAD_UPDATE, wxCommandEvent);
39 
41 class ThreadImage : public wxObject
42 {
43 public:
44  // explicit disable default contructor
45  ThreadImage() = delete;
46  // construct wxImage with given vigra image classes
47  ThreadImage(vigra::BRGBImage* thumbnail, vigra::BImage* mask)
48  {
49  // save pointer to raw image data for cleanup in destructor
50  m_preview = thumbnail;
51  m_mask = mask;
52  // construct wxImage, we keep track of the raw data
53  m_image=new wxImage(m_preview->width(), m_preview->height(), (unsigned char*)m_preview->data(), (unsigned char*)m_mask->data(), true);
54  }
55  // clean up
57  {
58  delete m_image;
59  delete m_preview;
60  delete m_mask;
61  }
62  // return pointer to wxImage
63  wxImage* GetwxImage() const { return m_image; }
64 private:
65  wxImage* m_image;
66  vigra::BRGBImage* m_preview;
67  vigra::BImage* m_mask;
68 };
69 
71 class ThumbnailThread : public wxThread
72 {
73 public:
74  ThumbnailThread(BrowsePTOFilesDialog* parentDialog, const wxArrayString& fileList, const wxSize size)
75  : wxThread(wxTHREAD_DETACHED)
76  {
77  m_parentDialog = parentDialog;
78  m_files = fileList;
79  m_thumbnailSize = size;
80  }
82  {
83  wxCriticalSectionLocker enter(m_parentDialog->m_ThreadCS);
84  // the thread is being destroyed; make sure not to leave dangling pointers around
86  }
87 
88 protected:
89  // main worker thread
90  virtual ExitCode Entry()
91  {
92  for (int i = 0; i < m_files.size(); ++i)
93  {
94  // generate thumbnail
95  vigra::BRGBImage* preview=new vigra::BRGBImage();
96  vigra::BImage* mask = new vigra::BImage();
97  vigra::ImageImportInfo::ICCProfile iccProfile;
98  if (!GenerateThumbnail(m_files[i].ToStdString(), m_thumbnailSize, *preview, *mask, iccProfile))
99  {
100  // generation of thumbnail failed, skip file
101  delete preview;
102  delete mask;
103  continue;
104  };
105  if (TestDestroy())
106  {
107  break;
108  };
109  // fit generated thumbnail into the full thumbnail rectangle
110  if (m_thumbnailSize.GetWidth() != preview->size().width() || m_thumbnailSize.GetHeight() != preview->size().height())
111  {
112  vigra::BRGBImage* scaledPreview = new vigra::BRGBImage(vigra::Diff2D(m_thumbnailSize.GetWidth(), m_thumbnailSize.GetHeight()), vigra::RGBValue<vigra::UInt8>(255, 255, 255));
113  vigra::BImage* scaledMask = new vigra::BImage(scaledPreview->size(), vigra::UInt8(0));
114  vigra::Point2D offset((scaledPreview->width() - preview->width()) / 2, (scaledPreview->height() - preview->height()) / 2);
115  vigra::copyImage(vigra::srcImageRange(*preview), vigra::destImage(*scaledPreview, offset));
116  vigra::copyImage(vigra::srcImageRange(*mask), vigra::destImage(*scaledMask, offset));
117  delete preview;
118  delete mask;
119  preview = scaledPreview;
120  mask = scaledMask;
121  }
122  // convert vigra image to wxImage
123  ThreadImage* thumbnailImageData = new ThreadImage(preview, mask);
124  // notify dialog about new available thumbnail
125  wxCommandEvent* event = new wxCommandEvent(wxEVT_COMMAND_THUMBNAILTHREAD_UPDATE);
126  event->SetInt(i);
127  event->SetEventObject(thumbnailImageData);
128  // check if we need to cancel
129  if (TestDestroy())
130  {
131  // we are destroying the thread
132  // clean up all unneeded pointer
133  delete event;
134  delete thumbnailImageData;
135  break;
136  }
137  else
138  {
139  // all ok, notify dialog to update its image list
140  wxQueueEvent(m_parentDialog, event);
141  };
142  };
143  return (wxThread::ExitCode)0;
144  }
145 
147  wxArrayString m_files;
149 };
150 
151 #define THUMBNAIL_SIZE 128
152 
153 #if !wxCHECK_VERSION(3,1,6)
154 // helper function to set image in header
155 void SetMyColumnImage(wxListCtrl* list, int col, int image)
156 {
157  wxListItem item;
158  item.SetMask(wxLIST_MASK_IMAGE);
159  item.SetImage(image);
160  list->SetColumn(col, item);
161 }
162 #endif
163 
164 BEGIN_EVENT_TABLE(BrowsePTOFilesDialog, wxDialog)
165  EVT_BUTTON(wxID_OK, BrowsePTOFilesDialog::OnOk)
166  EVT_BUTTON(XRCID("browse_show_map"), BrowsePTOFilesDialog::OnShowOnMap)
167  EVT_DIRCTRL_SELECTIONCHANGED(XRCID("browse_dirctrl"), BrowsePTOFilesDialog::OnDirectoryChanged)
168  EVT_LIST_ITEM_SELECTED(XRCID("browse_listctrl"), BrowsePTOFilesDialog::OnFileChanged)
169  EVT_LIST_COL_CLICK(XRCID("browse_listctrl"), BrowsePTOFilesDialog::OnListColClick)
170  EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_THUMBNAILTHREAD_UPDATE, BrowsePTOFilesDialog::OnThumbnailUpdate)
171  EVT_CHOICE(XRCID("browse_list_type"), BrowsePTOFilesDialog::OnListTypeChanged)
173 
174 BrowsePTOFilesDialog::BrowsePTOFilesDialog(wxWindow *parent, const wxString startDirectory)
175 {
176  // load our children. some children might need special
177  // initialization. this will be done later.
178  wxXmlResource::Get()->LoadDialog(this, parent, "browse_pto_dialog");
179 
180 #ifdef __WXMSW__
181  wxIconBundle myIcons(huginApp::Get()->GetXRCPath() + wxT("data/hugin.ico"),wxBITMAP_TYPE_ICO);
182  SetIcons(myIcons);
183 #else
184  wxIcon myIcon(huginApp::Get()->GetXRCPath() + wxT("data/hugin.png"),wxBITMAP_TYPE_PNG);
185  SetIcon(myIcon);
186 #endif
187  m_dirCtrl = XRCCTRL(*this, "browse_dirctrl", wxGenericDirCtrl);
188  m_listCtrl = XRCCTRL(*this, "browse_listctrl", wxListCtrl);
189  m_previewCtrl = XRCCTRL(*this, "browse_preview", wxStaticBitmap);
190  m_splitter1 = XRCCTRL(*this, "browse_splitter1", wxSplitterWindow);
191  m_splitter2 = XRCCTRL(*this, "browse_splitter2", wxSplitterWindow);
192  m_showMap = XRCCTRL(*this, "browse_show_map", wxButton);
193  m_labelControl = XRCCTRL(*this, "browse_statictext", wxStaticText);
194  m_labelControl->SetFont(m_labelControl->GetFont().Larger().Larger());
195  m_thumbnails.Create(THUMBNAIL_SIZE, THUMBNAIL_SIZE, true, 0);
196  m_listCtrl->SetWindowStyle(wxLC_REPORT | wxLC_AUTOARRANGE | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES);
197  m_listCtrl->SetImageList(&m_thumbnails, wxIMAGE_LIST_NORMAL);
198  m_listCtrl->Bind(wxEVT_LEFT_DCLICK, &BrowsePTOFilesDialog::OnDblClickListCtrl, this);
199  m_listCtrl->InsertColumn(0, _("Filename"), wxLIST_FORMAT_LEFT, 300);
200  m_listCtrl->InsertColumn(1, _("# images"), wxLIST_FORMAT_RIGHT, 50);
201  m_listCtrl->InsertColumn(2, _("# active images"), wxLIST_FORMAT_RIGHT, 50);
202  m_listCtrl->InsertColumn(3, _("Projection"), wxLIST_FORMAT_LEFT, 200);
203  m_listCtrl->InsertColumn(4, _("Field of view"), wxLIST_FORMAT_LEFT, 100);
204  m_listCtrl->InsertColumn(5, _("Canvas size"), wxLIST_FORMAT_LEFT, 100);
205  m_listCtrl->InsertColumn(6, _("Model"), wxLIST_FORMAT_LEFT, 200);
206  m_listCtrl->InsertColumn(7, _("Lens"), wxLIST_FORMAT_LEFT, 250);
207  m_listCtrl->InsertColumn(8, _("Focal length"), wxLIST_FORMAT_LEFT, 150);
208  m_listCtrl->InsertColumn(9, _("Capture date"), wxLIST_FORMAT_LEFT, 150);
209  m_listCtrl->InsertColumn(10, _("Duration"), wxLIST_FORMAT_LEFT, 50);
210  m_listType = XRCCTRL(*this, "browse_list_type", wxChoice);
211  // restore some settings
212  RestoreFramePosition(this, "BrowsePTODialog");
213  wxConfigBase* config = wxConfigBase::Get();
214  //splitter position
215  int splitter_pos = config->Read("/BrowsePTODialog/splitterPos1", -1l);
216  if (splitter_pos > 0)
217  {
218  m_splitter1->SetSashPosition(splitter_pos);
219  };
220  splitter_pos = config->Read("/BrowsePTODialog/splitterPos2", -1l);
221  if (splitter_pos > 0)
222  {
223  m_splitter2->SetSashPosition(splitter_pos);
224  };
225  //get saved width
226  for (int j = 0; j < m_listCtrl->GetColumnCount(); j++)
227  {
228  // -1 is auto
229  int width = config->Read(wxString::Format("/BrowsePTODialog/ColumnWidth%d", j), -1);
230  if (width != -1 && width > 5)
231  {
232  m_listCtrl->SetColumnWidth(j, width);
233  };
234  };
235  m_sortCol = config->Read("/BrowsePTODialog/SortColumn", -1);
236  m_sortAscending = config->Read("/BrowsePTODialog/SortAscending", 1) == 1 ? true : false;
237  if (m_sortCol != -1)
238  {
239 #if wxCHECK_VERSION(3,1,6)
240  m_listCtrl->ShowSortIndicator(m_sortCol, m_sortAscending);
241 #else
242  SetMyColumnImage(m_listCtrl, m_sortCol, m_sortAscending ? 0 : 1);
243 #endif
244  };
245 
246 #if !wxCHECK_VERSION(3,1,6)
247  // creating bitmaps for indicating sorting order
248  wxMemoryDC memDC;
249  memDC.SetFont(GetFont());
250  wxSize fontSize = memDC.GetTextExtent(wxT("\u25b3"));
251  wxCoord charSize = std::max(fontSize.GetWidth(), fontSize.GetHeight());
252  wxImageList* sortIcons = new wxImageList(charSize, charSize, true, 0);
253  {
254  wxBitmap bmp(charSize, charSize);
255  wxMemoryDC dc(bmp);
256  dc.SetBackgroundMode(wxPENSTYLE_TRANSPARENT);
257  dc.SetBackground(GetBackgroundColour());
258  dc.Clear();
259  dc.SetFont(GetFont());
260  dc.DrawText(wxT("\u25b3"), (charSize - fontSize.GetWidth()) / 2, (charSize - fontSize.GetHeight()) / 2);
261  dc.SelectObject(wxNullBitmap);
262  sortIcons->Add(bmp, GetBackgroundColour());
263  };
264  {
265  wxBitmap bmp(charSize, charSize);
266  wxMemoryDC dc(bmp);
267  dc.SetBackgroundMode(wxPENSTYLE_TRANSPARENT);
268  dc.SetBackground(GetBackgroundColour());
269  dc.Clear();
270  dc.SetFont(GetFont());
271  dc.DrawText(wxT("\u25bd"), (charSize - fontSize.GetWidth()) / 2, (charSize - fontSize.GetHeight()) / 2);
272  dc.SelectObject(wxNullBitmap);
273  sortIcons->Add(bmp, GetBackgroundColour());
274  };
275  m_listCtrl->AssignImageList(sortIcons, wxIMAGE_LIST_SMALL);
276 #endif
277 
278  // fill values for start directory
279  if (!startDirectory.IsEmpty())
280  {
281  m_dirCtrl->SetPath(startDirectory);
282  };
283  long listType = config->Read("/BrowsePTODialog/ListType", 0l);
284  m_listType->SetSelection(listType);
285  wxCommandEvent event;
286  event.SetInt(listType);
287  OnListTypeChanged(event);
288 };
289 
291 {
292  // stop working thread
294  // save some settings
295  StoreFramePosition(this, "BrowsePTODialog");
296  wxConfigBase* config = wxConfigBase::Get();
297  config->Write("/BrowsePTODialog/splitterPos1", m_splitter1->GetSashPosition());
298  config->Write("/BrowsePTODialog/splitterPos2", m_splitter2->GetSashPosition());
299  // save width of all columns in wxListCtrl
300  for (int j = 0; j < m_listCtrl->GetColumnCount(); j++)
301  {
302  config->Write(wxString::Format("/BrowsePTODialog/ColumnWidth%d", j), m_listCtrl->GetColumnWidth(j));
303  };
304  config->Write("/BrowsePTODialog/ListType", m_listType->GetSelection());
305  config->Write(wxT("/BrowsePTODialog/SortColumn"), m_sortCol);
306  config->Write(wxT("/BrowsePTODialog/SortAscending"), m_sortAscending ? 1 : 0);
307  config->Flush();
308 }
309 
311 {
312  long index = -1;
313  if (m_listCtrl->GetSelectedItemCount() == 1)
314  {
315  index = m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
316  };
317  if (index >= 0 && index < m_ptoInfo.size())
318  {
319  return m_ptoInfo[TranslateIndex(index)].ptoFilename.GetFullPath();
320  }
321  else
322  {
323  return wxEmptyString;
324  };
325 }
326 
328 {
329  return m_dirCtrl->GetPath();
330 }
331 
332 void BrowsePTOFilesDialog::OnOk(wxCommandEvent& e)
333 {
334  if (m_listCtrl->GetSelectedItemCount() == 1)
335  {
336  EndModal(wxID_OK);
337  }
338  else
339  {
340  wxBell();
341  }
342 }
343 
345 {
346  PanoInfo info;
347  info.ptoFilename = file;
348  // read pto file
349  HuginBase::Panorama pano;
350  const std::string input(file.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
351  if (!pano.ReadPTOFile(input, hugin_utils::getPathPrefix(input)))
352  {
353  return info;
354  };
355  // fill class to store some information about the pano
356  info.nrImages = pano.getNrOfImages();
357  info.nrActiveImages = pano.getActiveImages().size();
358  info.options = pano.getOptions();
359  // translate projection name
360  {
361  pano_projection_features proj;
362  wxString s;
363  if (panoProjectionFeaturesQuery(info.options.getProjection(), &proj))
364  {
365  wxString str2(proj.name, wxConvLocal);
366  info.projectionName = wxGetTranslation(str2);
367  };
368  };
369  // read some EXIF data
370  const HuginBase::UIntSet activeImages = pano.getActiveImages();
371  if (!activeImages.empty())
372  {
373  HuginBase::SrcPanoImage img0 = pano.getSrcImage(*activeImages.begin());
374  HuginBase::SrcPanoImage imgN = pano.getSrcImage(*activeImages.rbegin());
375  if(!hugin_utils::FileExists(img0.getFilename()))
376  {
377  return info;
378  }
379  img0.readEXIF();
380  info.camera = img0.getExifModel();
381  info.lens = img0.getExifLens();
382  info.focalLength35 = img0.getExifFocalLength35();
383  if (info.focalLength35 < 0.01 && img0.getCropFactor()>0)
384  {
385  info.focalLength35 = img0.getExifFocalLength() * img0.getCropFactor();
386  };
387  if (info.focalLength35 < 0.01)
388  {
389  info.focalLength35 = HuginBase::SrcPanoImage::calcFocalLength(img0.getProjection(), img0.getHFOV(), 1.0, img0.getSize());
390  };
392  if (!img0.getExifDate().empty())
393  {
394  struct tm exifdatetime0;
395  if (img0.getExifDateTime(&exifdatetime0) == 0)
396  {
397  info.start = wxDateTime(exifdatetime0);
398  };
399  if (!hugin_utils::FileExists(imgN.getFilename()))
400  {
401  return info;
402  };
403  imgN.readEXIF();
404  struct tm exifdatetimeN;
405  if (!imgN.getExifDate().empty() && imgN.getExifDateTime(&exifdatetimeN) == 0)
406  {
407  const wxDateTime endTime = wxDateTime(exifdatetimeN);
408  info.duration = endTime.Subtract(info.start);
409  };
410  };
411  const auto& fileMetadata = img0.getFileMetadata();
412  const auto& latitude = fileMetadata.find("latitude");
413  const auto& longitude = fileMetadata.find("longitude");
414  if (latitude != fileMetadata.end())
415  {
416  hugin_utils::stringToDouble(latitude->second, info.GPSLatitude);
417  };
418  if (longitude != fileMetadata.end())
419  {
420  hugin_utils::stringToDouble(longitude->second, info.GPSLongitude);
421  };
422  };
423  return info;
424 }
425 
426 wxString FormatDateTimeSpan(const wxTimeSpan timespan)
427 {
428  if (timespan.GetSeconds() > 60)
429  {
430  return timespan.Format(_("%M:%S min"));
431  }
432  else
433  {
434  if (timespan.GetSeconds() < 1)
435  {
436  return wxEmptyString;
437  }
438  else
439  {
440  return timespan.Format(_("%S s"));
441  };
442  };
443 }
444 
446 {
447 #ifndef __WXMSW__
448  // in generic implementation we can add text to column only in report view
449  if (m_listCtrl->InReportView())
450 #endif
451  {
452  m_listCtrl->SetItem(index, 1, wxString::Format("%zu", info.nrImages));
453  m_listCtrl->SetItem(index, 2, wxString::Format("%zu", info.nrActiveImages));
454  m_listCtrl->SetItem(index, 3, info.projectionName);
455  m_listCtrl->SetItem(index, 4, wxString::Format("%.0f x %.0f", info.options.getHFOV(), info.options.getVFOV()));
456  m_listCtrl->SetItem(index, 5, wxString::Format("%u x %u", info.options.getWidth(), info.options.getHeight()));
457  m_listCtrl->SetItem(index, 6, info.camera);
458  m_listCtrl->SetItem(index, 7, info.lens);
459  m_listCtrl->SetItem(index, 8, info.focalLengthString);
460  if (info.start.IsValid())
461  {
462  m_listCtrl->SetItem(index, 9, info.start.Format());
463  };
464  m_listCtrl->SetItem(index, 10, FormatDateTimeSpan(info.duration));
465  };
466 }
467 
469 {
470 #ifndef __WXMSW__
471  m_listCtrl->DeleteAllItems();
472 #endif
473  m_listCtrl->SetWindowStyle(newStyle);
474 #ifndef __WXMSW__
475  // changing the window style does invalidate the items, so we delete all items
476  // and add then again
477  for (size_t i = 0; i < m_ptoInfo.size(); ++i)
478  {
479  m_listCtrl->InsertItem(i, m_ptoInfo[i].ptoFilename.GetFullName(), -1);
480  m_listCtrl->SetItemData(i, i);
481  FillPanoInfo(m_ptoInfo[i], i);
482  };
483  SortItems();
484 #endif
485 }
486 
487 #if !wxCHECK_VERSION(3,1,6)
489 {
490  if (m_listCtrl->InReportView())
491  {
492  for (size_t i = 0; i < m_listCtrl->GetItemCount(); ++i)
493  {
494  // don't show images in report view
495  m_listCtrl->SetItemImage(i, -1);
496  };
497  }
498  else
499  {
500  // update image index only in icon view
501  for (size_t i = 0; i < m_listCtrl->GetItemCount(); ++i)
502  {
503  m_listCtrl->SetItemImage(i, m_ptoInfo[TranslateIndex(i)].imageIndex);
504  };
505  };
506 }
507 #endif
508 
510 {
511  if (m_dirCtrl && m_listCtrl)
512  {
513  wxWindowDisabler disableAll;
514  wxBusyInfo busy(wxBusyInfoFlags().Icon(MainFrame::Get()->GetIcon()).Label(wxString::Format(_("Reading directory %s"), m_dirCtrl->GetPath().c_str())));
515  // stop running thumbnail thread from last directory if not finished yet
517  // find all pto files in directory
518  m_ptoInfo.clear();
519  m_thumbnails.RemoveAll();
520  SetTitle(wxString::Format(_("Browse project files in %s"), m_dirCtrl->GetPath().c_str()));
521  wxArrayString files;
522  wxDir::GetAllFiles(m_dirCtrl->GetPath(), &files, "*.pto", wxDIR_FILES | wxDIR_HIDDEN | wxDIR_NO_FOLLOW);
523  // add to wxListCtrl
524  m_listCtrl->DeleteAllItems();
525  m_ptoInfo.resize(files.size());
526  for (size_t i = 0; i < files.size(); ++i)
527  {
528  const wxFileName filename(files[i]);
529  m_ptoInfo[i] = ParsePTOFile(filename);
530  m_listCtrl->InsertItem(i, m_ptoInfo[i].ptoFilename.GetFullName(), -1);
531  m_listCtrl->SetItemData(i, i);
532  FillPanoInfo(m_ptoInfo[i], i);
533  };
534  SortItems();
535  // start background thread for creating all thumbnails
536  m_thumbnailThread = new ThumbnailThread(this, files, m_thumbnails.GetSize());
537  if (!m_listCtrl->InReportView())
538  {
539  m_thumbnailThread->Run();
540  };
541  // clear preview area
542  m_previewCtrl->SetBitmap(wxBitmap());
543  m_previewCtrl->Show(true);
544  m_labelControl->Show(false);
545  m_showMap->Show(false);
546  m_showMap->Enable(false);
547  m_showMap->GetParent()->Layout();
548  };
549 }
550 
552 {
553  if (e.GetIndex() >= 0)
554  {
555  GeneratePreview(TranslateIndex(e.GetIndex()));
556  };
557 }
558 
560 {
561  if (m_listCtrl->GetSelectedItemCount() == 1)
562  {
563  EndModal(wxID_OK);
564  };
565 }
566 
568 {
569  const int newCol = e.GetColumn();
570 #if wxCHECK_VERSION(3,1,6)
571  if (m_sortCol == newCol)
572  {
574  }
575  else
576  {
577  m_sortCol = newCol;
578  m_sortAscending = true;
579  };
580  m_listCtrl->ShowSortIndicator(m_sortCol, m_sortAscending);
581 #else
582  if (m_sortCol == newCol)
583  {
586  }
587  else
588  {
589  if (m_sortCol != -1)
590  {
592  };
593  m_sortCol = newCol;
595  m_sortAscending = true;
596  };
597 #endif
598  SortItems();
599  Refresh();
600 }
601 
603 {
604  // we have created a new thumbnail, make the wxListCtrl aware of it
605  const int index = e.GetInt();
606  ThreadImage* thumbnail= wxDynamicCast(e.GetEventObject(), ThreadImage);
607  m_ptoInfo[index].imageIndex = m_thumbnails.Add(*(thumbnail->GetwxImage()));
608 #if wxCHECK_VERSION(3,1,6)
609  for (size_t i = 0; i < m_listCtrl->GetItemCount(); ++i)
610  {
611  if (m_listCtrl->GetItemData(i) == index)
612  {
613  m_listCtrl->SetItemImage(i, m_ptoInfo[index].imageIndex);
614  break;
615  };
616  };
617 #else
619 #endif
620  delete thumbnail;
621 #ifndef __WXMSW__
622  // a simple Refresh for repainting the control is not working
623  // all thumbnails are drawn on top of each other
624  // only when all done after a size event all is drawn correctly
625  m_listCtrl->SendSizeEvent();
626 #endif
627 }
628 
630 {
631  if (e.GetSelection() == 0)
632  {
633  UpdateItemTexts(wxLC_ICON | wxLC_AUTOARRANGE | wxLC_SINGLE_SEL);
634  // start creating thumbnail images in background thread
635  if (m_thumbnailThread && !m_thumbnailThread->IsRunning())
636  {
637  m_thumbnailThread->Run();
638  };
639  }
640  else
641  {
642  UpdateItemTexts(wxLC_REPORT | wxLC_AUTOARRANGE | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES);
643  };
644 #if !wxCHECK_VERSION(3,1,6)
646 #endif
647 #ifndef __WXMSW__
648  // a simple Refresh for repainting the control is not working
649  // all thumbnails are drawn on top of each other
650  // only when all done after a size event all is drawn correctly
651  m_listCtrl->SendSizeEvent();
652 #endif
653 }
654 
655 void BrowsePTOFilesDialog::OnShowOnMap(wxCommandEvent& e)
656 {
657  long index = -1;
658  if (m_listCtrl->GetSelectedItemCount() == 1)
659  {
660  index = m_listCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
661  };
662  if (index >= 0 && index < m_ptoInfo.size())
663  {
664  if (m_ptoInfo[index].HasGPS())
665  {
666  const wxString openstreetMapLink = "https://www.openstreetmap.org/?mlat=" + wxString::FromCDouble(m_ptoInfo[index].GPSLatitude) + "&mlon=" + wxString::FromCDouble(m_ptoInfo[index].GPSLongitude);
667  wxLaunchDefaultBrowser(openstreetMapLink);
668  }
669  }
670 }
671 
673 {
674  return m_listCtrl->GetItemData(index);
675 }
676 
677 template <class Type>
678 int GreaterComparisonOperator(const Type& a, const Type& b)
679 {
680  if (a > b)
681  {
682  return 1;
683  }
684  else
685  {
686  if (a < b)
687  {
688  return -1;
689  }
690  else {
691  return 0;
692  };
693  }
694 }
695 
696 template <class Type>
697 int SmallerComparisonOperator(const Type& a, const Type& b)
698 {
699  if (a < b)
700  {
701  return 1;
702  }
703  else
704  {
705  if (a > b)
706  {
707  return -1;
708  }
709  else {
710  return 0;
711  };
712  }
713 }
714 
715 #define SORTASCENDING(functionName, var) \
716 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
717 {\
718  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
719  return GreaterComparisonOperator(data->at(item1).var, data->at(item2).var);\
720 }
721 #define SORTDESCENDING(functionName, var) \
722 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
723 {\
724  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
725  return SmallerComparisonOperator(data->at(item1).var, data->at(item2).var);\
726 }
727 
728 SORTASCENDING(SortFilenameAscending, ptoFilename.GetFullName())
729 SORTDESCENDING(SortFilenameDescending, ptoFilename.GetFullName())
730 SORTASCENDING(SortNrImagesAscending, nrImages)
731 SORTDESCENDING(SortNrImagesDescending, nrImages)
732 SORTASCENDING(SortNrActiveImagesAscending, nrActiveImages)
733 SORTDESCENDING(SortNrActiveImagesDescending, nrActiveImages)
734 SORTASCENDING(SortProjectionAscending, projectionName)
735 SORTDESCENDING(SortProjectionDescending, projectionName)
736 SORTASCENDING(SortCanvasSizeAcending, options.getSize().area())
737 SORTDESCENDING(SortCanvasSizeDescending, options.getSize().area())
738 SORTASCENDING(SortFocalLengthAscending, focalLength35)
739 SORTDESCENDING(SortFocalLengthDescending, focalLength35)
740 
741 #undef SORTASCENDING
742 #undef SORTDESCENDING
743 
744 // special variant for wxStrings
745 #define SORTASCENDING(functionName, var) \
746 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
747 {\
748  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
749  return data->at(item1).var.CmpNoCase(data->at(item2).var);\
750 }
751 #define SORTDESCENDING(functionName, var) \
752 int wxCALLBACK functionName(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\
753 {\
754  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);\
755  return -(data->at(item1).var.CmpNoCase(data->at(item2).var));\
756 }
757 SORTASCENDING(SortCameraAscending, camera)
758 SORTDESCENDING(SortCameraDescending, camera)
759 SORTASCENDING(SortLensAscending, lens)
760 SORTDESCENDING(SortLensDescending, lens)
761 
762 #undef SORTASCENDING
763 #undef SORTDESCENDING
764 
765 // sort by field of view
766 int wxCALLBACK SortFieldOfViewAscending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
767 {
768  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
769  const float fieldOfView1 = data->at(item1).options.getHFOV() * 1000 + data->at(item1).options.getVFOV();
770  const float fieldOfView2 = data->at(item2).options.getHFOV() * 1000 + data->at(item2).options.getVFOV();
771  return GreaterComparisonOperator(fieldOfView1, fieldOfView2);
772 }
773 
774 int wxCALLBACK SortFieldOfViewDescending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
775 {
776  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
777  const float fieldOfView1 = data->at(item1).options.getHFOV() * 1000 + data->at(item1).options.getVFOV();
778  const float fieldOfView2 = data->at(item2).options.getHFOV() * 1000 + data->at(item2).options.getVFOV();
779  return SmallerComparisonOperator(fieldOfView1, fieldOfView2);
780 }
781 
782 // sort by date
783 int wxCALLBACK SortDateAscending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
784 {
785  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
786  if (data->at(item1).start.IsLaterThan(data->at(item2).start))
787  {
788  return 1;
789  }
790  if (data->at(item1).start.IsEarlierThan(data->at(item2).start))
791  {
792  return -1;
793  }
794  return 0;
795 };
796 
797 int wxCALLBACK SortDateDesending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
798 {
799  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
800  if (data->at(item1).start.IsEarlierThan(data->at(item2).start))
801  {
802  return 1;
803  }
804  if (data->at(item1).start.IsLaterThan(data->at(item2).start))
805  {
806  return -1;
807  }
808  return 0;
809 };
810 
811 // sort by duration
812 int wxCALLBACK SortDurationAscending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
813 {
814  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
815  if (data->at(item1).duration.IsLongerThan(data->at(item2).duration))
816  {
817  return 1;
818  }
819  if (data->at(item1).duration.IsShorterThan(data->at(item2).duration))
820  {
821  return -1;
822  }
823  return 0;
824 };
825 
826 int wxCALLBACK SortDurationDesending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
827 {
828  std::vector<PanoInfo>* data = (std::vector<PanoInfo>*)(sortData);
829  if (data->at(item1).duration.IsShorterThan(data->at(item2).duration))
830  {
831  return 1;
832  }
833  if (data->at(item1).duration.IsLongerThan(data->at(item2).duration))
834  {
835  return -1;
836  }
837  return 0;
838 };
839 
841 {
842  if (m_sortCol > -1)
843  {
844  switch (m_sortCol)
845  {
846  default:
847  case 0: // filename
848  if (m_sortAscending)
849  {
850  m_listCtrl->SortItems(SortFilenameAscending, wxIntPtr(&m_ptoInfo));
851  }
852  else
853  {
854  m_listCtrl->SortItems(SortFilenameDescending, wxIntPtr(&m_ptoInfo));
855  };
856  break;
857  case 1: // number of images
858  if (m_sortAscending)
859  {
860  m_listCtrl->SortItems(SortNrImagesAscending, wxIntPtr(&m_ptoInfo));
861  }
862  else
863  {
864  m_listCtrl->SortItems(SortNrImagesDescending, wxIntPtr(&m_ptoInfo));
865  };
866  break;
867  case 2: // number of active images
868  if (m_sortAscending)
869  {
870  m_listCtrl->SortItems(SortNrActiveImagesAscending, wxIntPtr(&m_ptoInfo));
871  }
872  else
873  {
874  m_listCtrl->SortItems(SortNrActiveImagesDescending, wxIntPtr(&m_ptoInfo));
875  };
876  break;
877  case 3: // projection
878  if (m_sortAscending)
879  {
880  m_listCtrl->SortItems(SortProjectionAscending, wxIntPtr(&m_ptoInfo));
881  }
882  else
883  {
884  m_listCtrl->SortItems(SortProjectionDescending, wxIntPtr(&m_ptoInfo));
885  };
886  break;
887  case 4: // field of view
888  if (m_sortAscending)
889  {
890  m_listCtrl->SortItems(SortFieldOfViewAscending, wxIntPtr(&m_ptoInfo));
891  }
892  else
893  {
894  m_listCtrl->SortItems(SortFieldOfViewDescending, wxIntPtr(&m_ptoInfo));
895  };
896  break;
897  case 5: // canvas size
898  if (m_sortAscending)
899  {
900  m_listCtrl->SortItems(SortCanvasSizeAcending, wxIntPtr(&m_ptoInfo));
901  }
902  else
903  {
904  m_listCtrl->SortItems(SortCanvasSizeDescending, wxIntPtr(&m_ptoInfo));
905  };
906  break;
907  case 6: // model
908  if (m_sortAscending)
909  {
910  m_listCtrl->SortItems(SortCameraAscending, wxIntPtr(&m_ptoInfo));
911  }
912  else
913  {
914  m_listCtrl->SortItems(SortCameraDescending, wxIntPtr(&m_ptoInfo));
915  };
916  break;
917  case 7: // lens
918  if (m_sortAscending)
919  {
920  m_listCtrl->SortItems(SortLensAscending, wxIntPtr(&m_ptoInfo));
921  }
922  else
923  {
924  m_listCtrl->SortItems(SortLensDescending, wxIntPtr(&m_ptoInfo));
925  };
926  break;
927  case 8: // focal length
928  if (m_sortAscending)
929  {
930  m_listCtrl->SortItems(SortFocalLengthAscending, wxIntPtr(&m_ptoInfo));
931  }
932  else
933  {
934  m_listCtrl->SortItems(SortFocalLengthDescending, wxIntPtr(&m_ptoInfo));
935  };
936  break;
937  case 9: // capture date
938  if (m_sortAscending)
939  {
940  m_listCtrl->SortItems(SortDateAscending, wxIntPtr(&m_ptoInfo));
941  }
942  else
943  {
944  m_listCtrl->SortItems(SortDateDesending, wxIntPtr(&m_ptoInfo));
945  };
946  break;
947  case 10: // duration
948  if (m_sortAscending)
949  {
950  m_listCtrl->SortItems(SortDurationAscending, wxIntPtr(&m_ptoInfo));
951  }
952  else
953  {
954  m_listCtrl->SortItems(SortDurationDesending, wxIntPtr(&m_ptoInfo));
955  };
956  break;
957  };
958  };
959 };
960 
962 {
963  // delete running background thread
964  wxBusyCursor busy;
965  {
966  bool deleteStoppedThread = false;
967  {
968  wxCriticalSectionLocker enter(m_ThreadCS);
969  if (m_thumbnailThread)
970  {
971  if (m_thumbnailThread->IsRunning())
972  {
973  m_thumbnailThread->Delete();
974  }
975  else
976  {
977  deleteStoppedThread = true;
978  };
979  };
980  };
981  if (deleteStoppedThread)
982  {
983  delete m_thumbnailThread;
984  };
985  };
986  // exit from the critical section to give the thread
987  // the possibility to enter its destructor
988  // (which is guarded with m_ThreadCS critical section!)
989  while (1)
990  {
991  {
992  wxCriticalSectionLocker enter(m_ThreadCS);
993  if (!m_thumbnailThread)
994  {
995  break;
996  };
997  };
998  // wait for thread completion
999  wxThread::This()->Sleep(1);
1000  };
1001 }
1002 
1004 {
1005  if (index<0 || index>m_ptoInfo.size())
1006  {
1007  return;
1008  };
1009  wxWindowDisabler disableAll;
1010  wxBusyInfo busyInfo(wxBusyInfoFlags().Icon(MainFrame::Get()->GetIcon()).Label(wxString::Format(_("Generating preview for %s"), m_ptoInfo[index].ptoFilename.GetFullName().c_str())));
1011  wxSize previewSize = m_previewCtrl->GetParent()->GetSize();
1012  vigra::BRGBImage preview;
1013  vigra::BImage mask;
1014  vigra::ImageImportInfo::ICCProfile iccProfile;
1015  if (GenerateThumbnail(m_ptoInfo[index].ptoFilename.GetFullPath().ToStdString(), previewSize, preview, mask, iccProfile))
1016  {
1017  wxImage image(preview.width(), preview.height(), (unsigned char*)preview.data(), (unsigned char*)mask.data(), true);
1018  // now apply color profile
1019  if (!iccProfile.empty() || huginApp::Get()->HasMonitorProfile())
1020  {
1022  };
1023  // now show in GUI
1024  m_previewCtrl->SetBitmap(image);
1025  m_previewCtrl->Show(true);
1026  m_labelControl->Show(false);
1027  m_showMap->Show(m_ptoInfo[index].HasGPS());
1028  m_showMap->Enable(m_ptoInfo[index].HasGPS());
1029  m_showMap->GetParent()->Layout();
1030  }
1031  else
1032  {
1033  // could not create preview, disable control and show error message
1034  m_previewCtrl->Show(false);
1035  m_labelControl->Show(true);
1036  m_showMap->Show(false);
1037  m_showMap->Enable(false);
1038  m_showMap->GetParent()->Layout();
1039  };
1040  Update();
1041 }
wxDEFINE_EVENT(EVT_QUEUE_PROGRESS, wxCommandEvent)
~BrowsePTOFilesDialog()
destructor, saves position
PanoramaOptions::ProjectionFormat getProjection() const
implementation of huginApp Class
generate thumbnail from given pto file
bool FileExists(const std::string &filename)
checks if file exists
Definition: utils.cpp:362
const float fieldOfView1
wxListCtrl * m_listCtrl
Definition: BrowseDialog.h:124
int SmallerComparisonOperator(const Type &a, const Type &b)
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
Definition: Panorama.cpp:1620
size_t nrActiveImages
Definition: BrowseDialog.h:53
#define THUMBNAIL_SIZE
#define HUGIN_CONV_FILENAME
Definition: platform.h:40
virtual ExitCode Entry()
unsigned int getHeight() const
get panorama height
some helper classes for graphes
int wxCALLBACK SortFieldOfViewDescending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
ThumbnailThread(BrowsePTOFilesDialog *parentDialog, const wxArrayString &fileList, const wxSize size)
void FillPanoInfo(const PanoInfo &info, long index)
add a new item to wxListCtrl and populate all columns
#define SORTASCENDING(functionName, var)
double focalLength35
Definition: BrowseDialog.h:60
END_EVENT_TABLE()
void OnFileChanged(wxListEvent &e)
new file selected, generate preview for new file
friend class ThumbnailThread
Definition: BrowseDialog.h:142
wxString projectionName
Definition: BrowseDialog.h:55
void SetMyColumnImage(wxListCtrl *list, int col, int image)
double GPSLongitude
Definition: BrowseDialog.h:63
void OnThumbnailUpdate(wxCommandEvent &e)
for notifing from ThumbnailThread about new generated thumbnail generated thumbnail is transfered in ...
wxString lens
Definition: BrowseDialog.h:59
void GetMonitorProfile(wxString &profileName, cmsHPROFILE &profile)
Definition: wxcms.cpp:195
wxImage * GetwxImage() const
static huginApp * Get()
hack.. kind of a pseudo singleton...
Definition: huginApp.cpp:649
void OnDblClickListCtrl(wxMouseEvent &e)
double click does open file
std::set< unsigned int > UIntSet
Definition: PanoramaData.h:51
wxSplitterWindow * m_splitter1
Definition: BrowseDialog.h:132
PanoInfo ParsePTOFile(const wxFileName file)
read the given pto file and add all information to wxListCtrl
options getSize().area()) int wxCALLBACK SortFieldOfViewAscending(wxIntPtr item1
Model for a panorama.
Definition: Panorama.h:152
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
Definition: utils.cpp:184
int wxCALLBACK SortDateAscending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
void OnListColClick(wxListEvent &e)
click on header to sort by column
void CorrectImage(wxImage &image, const vigra::ImageImportInfo::ICCProfile &iccProfile, const cmsHPROFILE &monitorProfile)
apply color correction to given image using input iccProfile and monitor profile
Definition: wxcms.cpp:218
wxString focalLengthString
Definition: BrowseDialog.h:61
std::size_t getNrOfImages() const
number of images.
Definition: Panorama.h:205
static MainFrame * Get()
hack.. kind of a pseudo singleton...
Definition: MainFrame.cpp:2181
wxStaticText * m_labelControl
Definition: BrowseDialog.h:131
int wxCALLBACK SortDurationAscending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
wxString camera
Definition: BrowseDialog.h:58
#define SORTDESCENDING(functionName, var)
const int getExifDateTime(struct tm *datetime) const
try to convert Exif date time string to struct tm
Dialog for browsing pto files.
Definition: BrowseDialog.h:72
void StoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Store window size and position in configfile/registry.
Definition: LensCalApp.cpp:212
wxGenericDirCtrl * m_dirCtrl
Definition: BrowseDialog.h:123
vigra::BRGBImage * m_preview
bool ReadPTOFile(const std::string &filename, const std::string &prefix="")
read pto file from the given filename into Panorama object it does some checks on the file and issues...
Definition: Panorama.cpp:2023
void OnDirectoryChanged(wxTreeEvent &e)
directory changed, load files from new directory
wxImageList m_thumbnails
image list with all thumbnails
Definition: BrowseDialog.h:137
helper class to transfer thumbnail data from worker thread to GUI thread
bool HasMonitorProfile() const
return true if we found a suitable monitor profile and could loading it
Definition: huginApp.h:156
wxString FormatDateTimeSpan(const wxTimeSpan timespan)
wxDECLARE_EVENT(wxEVT_COMMAND_THUMBNAILTHREAD_UPDATE, wxCommandEvent)
HuginBase::PanoramaOptions options
Definition: BrowseDialog.h:54
void RestoreFramePosition(wxTopLevelWindow *frame, const wxString &basename)
Restore window size and position from configfile/registry.
Definition: LensCalApp.cpp:158
void GeneratePreview(int index)
generate preview for pto file with index
options wxIntPtr item2
wxArrayString m_files
wxSplitterWindow * m_splitter2
Definition: BrowseDialog.h:133
const float fieldOfView2
static double calcFocalLength(SrcPanoImage::Projection proj, double hfov, double crop, vigra::Size2D imageSize)
calcualte focal length, given crop factor and hfov
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
Definition: ROIImage.h:324
bool stringToDouble(const STR &str_, double &dest)
convert a string to a double, ignore localisation.
Definition: utils.h:114
std::vector< PanoInfo > m_ptoInfo
info about the pto file
Definition: BrowseDialog.h:135
void SortItems()
sort the items according to selected column
vigra::triple< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImageRange(const ROIImage< Image, Mask > &img)
helper function for ROIImages
Definition: ROIImage.h:287
wxDateTime start
Definition: BrowseDialog.h:56
UIntSet getActiveImages() const
get active images
Definition: Panorama.cpp:1585
wxString GetSelectedProject()
return full path of selected project
wxImage * m_image
wxFileName ptoFilename
Definition: BrowseDialog.h:49
unsigned int getWidth() const
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition: Panorama.h:481
wxCriticalSection m_ThreadCS
critical section to synchronize with ThumbnailThread
Definition: BrowseDialog.h:141
options wxIntPtr wxIntPtr sortData std::vector< PanoInfo > * data
background thread to generate thumbnails of all pto files
void UpdateImagesIndex()
update the image indexes
wxStaticBitmap * m_previewCtrl
Definition: BrowseDialog.h:130
size_t nrImages
Definition: BrowseDialog.h:51
static T max(T x, T y)
Definition: svm.cpp:65
bool readEXIF()
try to fill out information about the image, by examining the exif data
bool GenerateThumbnail(const std::string pto_filename, const wxSize size, vigra::BRGBImage &panoImage, vigra::BImage &panoMask, vigra::ImageImportInfo::ICCProfile &iccProfile)
generate thumbnail image for given pto_filename
Definition of dialog to browse directory with pto files.
void OnListTypeChanged(wxCommandEvent &e)
Change display of wxListCtrl.
int wxCALLBACK SortDateDesending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
void copyImage(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor src_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc)
Definition: openmp_vigra.h:305
BrowsePTOFilesDialog * m_parentDialog
static void info(const char *fmt,...)
Definition: svm.cpp:95
class to store some information about a pto file on disc
Definition: BrowseDialog.h:46
double GPSLatitude
Definition: BrowseDialog.h:64
void OnOk(wxCommandEvent &e)
Saves current expression when closing dialog with Ok.
wxString GetFocalLength(const HuginBase::SrcPanoImage *img)
return focallength and focallength 35 mm as wxString
Definition: LensTools.cpp:519
ThreadImage(vigra::BRGBImage *thumbnail, vigra::BImage *mask)
ThreadImage()=delete
int GreaterComparisonOperator(const Type &a, const Type &b)
All variables of a source image.
Definition: SrcPanoImage.h:194
ThumbnailThread * m_thumbnailThread
background thumbnail creater thread
Definition: BrowseDialog.h:139
long TranslateIndex(const long index)
translate the index to the index of m_ptoInfo
wxTimeSpan duration
Definition: BrowseDialog.h:57
int wxCALLBACK SortDurationDesending(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
void OnShowOnMap(wxCommandEvent &e)
show current pano on Openstreetmap
void EndThumbnailThread()
end background thumbnail creating thread
void UpdateItemTexts(long newStyle)
update all item texts
vigra::BImage * m_mask
wxString GetSelectedPath()
return last selected path