MainFrame.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00027 #include <config.h>
00028 #include <exiv2/exif.hpp>
00029 #include <exiv2/image.hpp>
00030 
00031 #include <wx/dir.h>
00032 #include <wx/stdpaths.h>
00033 #include "panoinc_WX.h"
00034 #include "panoinc.h"
00035 
00036 #include "base_wx/platform.h"
00037 #include "base_wx/wxPlatform.h"
00038 
00039 #include "vigra/imageinfo.hxx"
00040 #include "vigra_ext/Correlation.h"
00041 
00042 #include "hugin/config_defaults.h"
00043 #include "hugin/PreferencesDialog.h"
00044 #include "hugin/MainFrame.h"
00045 #include "base_wx/wxPanoCommand.h"
00046 #include "base_wx/CommandHistory.h"
00047 #include "hugin/PanoPanel.h"
00048 #include "hugin/ImagesPanel.h"
00049 #include "hugin/MaskEditorPanel.h"
00050 #include "hugin/OptimizePanel.h"
00051 #include "hugin/OptimizePhotometricPanel.h"
00052 #include "hugin/PreviewFrame.h"
00053 #include "hugin/GLPreviewFrame.h"
00054 #include "hugin/huginApp.h"
00055 #include "hugin/CPEditorPanel.h"
00056 #include "hugin/CPListFrame.h"
00057 #include "hugin/LocalizedFileTipProvider.h"
00058 #include "algorithms/control_points/CleanCP.h"
00059 #include "hugin/PanoOperation.h"
00060 #include "hugin/PapywizardImport.h"
00061 
00062 #include "base_wx/MyProgressDialog.h"
00063 #include "base_wx/RunStitchPanel.h"
00064 #include "base_wx/wxImageCache.h"
00065 #include "base_wx/PTWXDlg.h"
00066 #include "base_wx/MyExternalCmdExecDialog.h"
00067 #include "base_wx/AssistantExecutor.h"
00068 #include "algorithms/optimizer/ImageGraph.h"
00069 
00070 #include "base_wx/huginConfig.h"
00071 #include "hugin/AboutDialog.h"
00072 
00073 #if HUGIN_HSI
00074 #include "PluginItems.h"
00075 #endif
00076 
00077 #ifdef __MINGW32__
00078 // fixes for mingw compilation...
00079 #undef FindWindow
00080 #endif
00081 
00086 class HuginSplashScreen : public wxFrame
00087 {
00088 public:
00089     HuginSplashScreen() {};
00090     HuginSplashScreen(wxWindow* parent, wxBitmap bitmap) : 
00091         wxFrame(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxFRAME_TOOL_WINDOW | wxFRAME_NO_TASKBAR | wxSTAY_ON_TOP)
00092     {
00093         SetExtraStyle(GetExtraStyle() | wxWS_EX_TRANSIENT);
00094         wxSizer* topSizer=new wxBoxSizer(wxVERTICAL);
00095         wxStaticBitmap* staticBitmap=new wxStaticBitmap(this,wxID_ANY,bitmap);
00096         topSizer->Add(staticBitmap,1,wxEXPAND);
00097         SetSizerAndFit(topSizer);
00098         SetClientSize(bitmap.GetWidth(), bitmap.GetHeight());
00099         CenterOnScreen();
00100         Show(true);
00101         SetFocus();
00102 #if defined(__WXMSW__) || defined(__WXMAC__)
00103         Update();
00104 #elif defined(__WXGTK20__)
00105         //do nothing
00106 #else
00107         wxYieldIfNeeded();
00108 #endif
00109     };
00110     DECLARE_DYNAMIC_CLASS(HuginSplashScreen)
00111     DECLARE_EVENT_TABLE()
00112 };
00113 
00114 IMPLEMENT_DYNAMIC_CLASS(HuginSplashScreen, wxFrame)
00115 BEGIN_EVENT_TABLE(HuginSplashScreen, wxFrame)
00116 END_EVENT_TABLE()
00117 
00119 bool PanoDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames)
00120 {
00121     DEBUG_TRACE("OnDropFiles");
00122     MainFrame * mf = MainFrame::Get();
00123     if (!mf) return false;
00124 
00125     if (!m_imageOnly && filenames.GetCount() == 1) {
00126         wxFileName file(filenames[0]);
00127         if (file.GetExt().CmpNoCase(wxT("pto")) == 0 ||
00128             file.GetExt().CmpNoCase(wxT("ptp")) == 0 ||
00129             file.GetExt().CmpNoCase(wxT("pts")) == 0 )
00130         {
00131             // load project
00132             if (mf->CloseProject(true)) {
00133                 mf->LoadProjectFile(file.GetFullPath());
00134                 // remove old images from cache
00135                 ImageCache::getInstance().flush();
00136             }
00137             return true;
00138         }
00139     }
00140 
00141     // try to add as images
00142     std::vector<std::string> filesv;
00143     wxArrayString invalidFiles;
00144     for (unsigned int i=0; i< filenames.GetCount(); i++) {
00145         wxFileName file(filenames[i]);
00146 
00147         if (file.GetExt().CmpNoCase(wxT("jpg")) == 0 ||
00148             file.GetExt().CmpNoCase(wxT("jpeg")) == 0 ||
00149             file.GetExt().CmpNoCase(wxT("tif")) == 0 ||
00150             file.GetExt().CmpNoCase(wxT("tiff")) == 0 ||
00151             file.GetExt().CmpNoCase(wxT("png")) == 0 ||
00152             file.GetExt().CmpNoCase(wxT("bmp")) == 0 ||
00153             file.GetExt().CmpNoCase(wxT("gif")) == 0 ||
00154             file.GetExt().CmpNoCase(wxT("pnm")) == 0 ||
00155             file.GetExt().CmpNoCase(wxT("sun")) == 0 ||
00156             file.GetExt().CmpNoCase(wxT("hdr")) == 0 ||
00157             file.GetExt().CmpNoCase(wxT("viff")) == 0 )
00158         {
00159             if(containsInvalidCharacters(filenames[i]))
00160             {
00161                 invalidFiles.Add(file.GetFullPath());
00162             }
00163             else
00164             {
00165                 filesv.push_back((const char *)filenames[i].mb_str(HUGIN_CONV_FILENAME));
00166             };
00167         }
00168     }
00169     // we got some images to add.
00170     if (filesv.size() > 0)
00171     {
00172         // use a Command to ensure proper undo and updating of GUI parts
00173         wxBusyCursor();
00174         if(pano.getNrOfCtrlPoints()>0)
00175         {
00176             PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::wxAddImagesCmd(pano, filesv));
00177         }
00178         else
00179         {
00180             std::vector<PanoCommand::PanoCommand*> cmds;
00181             cmds.push_back(new PanoCommand::wxAddImagesCmd(pano, filesv));
00182             cmds.push_back(new PanoCommand::DistributeImagesCmd(pano));
00183             cmds.push_back(new PanoCommand::CenterPanoCmd(pano));
00184             PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::CombinedPanoCommand(pano, cmds));
00185         };
00186 
00187     }
00188     if(invalidFiles.size()>0)
00189     {
00190         ShowFilenameWarning(mf, invalidFiles);
00191     }
00192 
00193     return true;
00194 }
00195 
00196 
00197 
00198 // event table. this frame will recieve mostly global commands.
00199 BEGIN_EVENT_TABLE(MainFrame, wxFrame)
00200     EVT_MENU(XRCID("action_new_project"),  MainFrame::OnNewProject)
00201     EVT_MENU(XRCID("action_load_project"),  MainFrame::OnLoadProject)
00202     EVT_MENU(XRCID("action_save_project"),  MainFrame::OnSaveProject)
00203     EVT_MENU(XRCID("action_save_as_project"),  MainFrame::OnSaveProjectAs)
00204     EVT_MENU(XRCID("action_save_as_ptstitcher"),  MainFrame::OnSavePTStitcherAs)
00205     EVT_MENU(XRCID("action_open_batch_processor"),  MainFrame::OnOpenPTBatcher)
00206     EVT_MENU(XRCID("action_import_project"), MainFrame::OnMergeProject)
00207     EVT_MENU(XRCID("action_import_papywizard"), MainFrame::OnReadPapywizard)
00208     EVT_MENU(XRCID("action_apply_template"),  MainFrame::OnApplyTemplate)
00209     EVT_MENU(XRCID("action_exit_hugin"),  MainFrame::OnUserQuit)
00210     EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, MainFrame::OnMRUFiles)
00211     EVT_MENU(XRCID("action_show_about"),  MainFrame::OnAbout)
00212     EVT_MENU(XRCID("action_show_help"),  MainFrame::OnHelp)
00213     EVT_MENU(XRCID("action_show_tip"),  MainFrame::OnTipOfDay)
00214     EVT_MENU(XRCID("action_show_shortcuts"),  MainFrame::OnKeyboardHelp)
00215     EVT_MENU(XRCID("action_show_faq"),  MainFrame::OnFAQ)
00216     EVT_MENU(XRCID("action_show_donate"),  MainFrame::OnShowDonate)
00217     EVT_MENU(XRCID("action_show_prefs"), MainFrame::OnShowPrefs)
00218     EVT_MENU(XRCID("action_assistant"), MainFrame::OnRunAssistant)
00219     EVT_MENU(XRCID("action_batch_assistant"), MainFrame::OnSendToAssistantQueue)
00220     EVT_MENU(XRCID("action_gui_simple"), MainFrame::OnSetGuiSimple)
00221     EVT_MENU(XRCID("action_gui_advanced"), MainFrame::OnSetGuiAdvanced)
00222     EVT_MENU(XRCID("action_gui_expert"), MainFrame::OnSetGuiExpert)
00223 #ifdef HUGIN_HSI
00224     EVT_MENU(XRCID("action_python_script"), MainFrame::OnPythonScript)
00225 #endif
00226     EVT_MENU(XRCID("ID_EDITUNDO"), MainFrame::OnUndo)
00227     EVT_MENU(XRCID("ID_EDITREDO"), MainFrame::OnRedo)
00228     EVT_MENU(XRCID("ID_SHOW_FULL_SCREEN"), MainFrame::OnFullScreen)
00229     EVT_MENU(XRCID("ID_SHOW_PREVIEW_FRAME"), MainFrame::OnTogglePreviewFrame)
00230     EVT_MENU(XRCID("ID_SHOW_GL_PREVIEW_FRAME"), MainFrame::OnToggleGLPreviewFrame)
00231     EVT_BUTTON(XRCID("ID_SHOW_PREVIEW_FRAME"),MainFrame::OnTogglePreviewFrame)
00232     EVT_BUTTON(XRCID("ID_SHOW_GL_PREVIEW_FRAME"), MainFrame::OnToggleGLPreviewFrame)
00233 
00234     EVT_MENU(XRCID("action_optimize"),  MainFrame::OnOptimize)
00235     EVT_MENU(XRCID("action_optimize_only_active"), MainFrame::OnOnlyActiveImages)
00236     EVT_BUTTON(XRCID("action_optimize"),  MainFrame::OnOptimize)
00237     EVT_MENU(XRCID("action_finetune_all_cp"), MainFrame::OnFineTuneAll)
00238 //    EVT_BUTTON(XRCID("action_finetune_all_cp"), MainFrame::OnFineTuneAll)
00239     EVT_MENU(XRCID("action_remove_cp_in_masks"), MainFrame::OnRemoveCPinMasks)
00240 
00241     EVT_MENU(XRCID("ID_CP_TABLE"), MainFrame::OnShowCPFrame)
00242     EVT_BUTTON(XRCID("ID_CP_TABLE"),MainFrame::OnShowCPFrame)
00243 
00244     EVT_MENU(XRCID("ID_SHOW_PANEL_IMAGES"), MainFrame::OnShowPanel)
00245     EVT_MENU(XRCID("ID_SHOW_PANEL_MASK"), MainFrame::OnShowPanel)
00246     EVT_MENU(XRCID("ID_SHOW_PANEL_CP_EDITOR"), MainFrame::OnShowPanel)
00247     EVT_MENU(XRCID("ID_SHOW_PANEL_OPTIMIZER"), MainFrame::OnShowPanel)
00248     EVT_MENU(XRCID("ID_SHOW_PANEL_OPTIMIZER_PHOTOMETRIC"), MainFrame::OnShowPanel)
00249     EVT_MENU(XRCID("ID_SHOW_PANEL_PANORAMA"), MainFrame::OnShowPanel)
00250     EVT_MENU(XRCID("action_stitch"), MainFrame::OnDoStitch)
00251     EVT_MENU(XRCID("action_stitch_userdefined"), MainFrame::OnUserDefinedStitch)
00252     EVT_MENU(XRCID("action_add_images"),  MainFrame::OnAddImages)
00253     EVT_BUTTON(XRCID("action_add_images"),  MainFrame::OnAddImages)
00254     EVT_MENU(XRCID("action_add_time_images"),  MainFrame::OnAddTimeImages)
00255     EVT_BUTTON(XRCID("action_add_time_images"),  MainFrame::OnAddTimeImages)
00256     EVT_CLOSE(  MainFrame::OnExit)
00257     EVT_SIZE(MainFrame::OnSize)
00258 END_EVENT_TABLE()
00259 
00260 // change this variable definition
00261 //wxTextCtrl *itemProjTextMemo;
00262 // image preview
00263 //wxBitmap *p_img = (wxBitmap *) NULL;
00264 //WX_DEFINE_ARRAY()
00265 
00266 MainFrame::MainFrame(wxWindow* parent, HuginBase::Panorama & pano)
00267     : cp_frame(0), pano(pano)
00268 {
00269     preview_frame = 0;
00270     svmModel=NULL;
00271 
00272     bool disableOpenGL=false;
00273 #if wxCHECK_VERSION(2,9,4)
00274     if(wxGetKeyState(WXK_COMMAND))
00275 #else
00276     if(wxGetKeyState(WXK_CONTROL))
00277 #endif
00278     {
00279         wxDialog dlg;
00280         wxXmlResource::Get()->LoadDialog(&dlg, NULL, wxT("disable_opengl_dlg"));
00281         long noOpenGL=wxConfigBase::Get()->Read(wxT("DisableOpenGL"), 0l);
00282         if(noOpenGL==1)
00283         {
00284             XRCCTRL(dlg, "disable_dont_ask_checkbox", wxCheckBox)->SetValue(true);
00285         };
00286         if(dlg.ShowModal()==wxID_OK)
00287         {
00288             if(XRCCTRL(dlg, "disable_dont_ask_checkbox", wxCheckBox)->IsChecked())
00289             {
00290                 wxConfigBase::Get()->Write(wxT("DisableOpenGL"), 1l);
00291             }
00292             else
00293             {
00294                 wxConfigBase::Get()->Write(wxT("DisableOpenGL"), 0l);
00295             };
00296             disableOpenGL=true;
00297         }
00298         else
00299         {
00300             wxConfigBase::Get()->Write(wxT("DisableOpenGL"), 0l);
00301         };
00302     }
00303     else
00304     {
00305         long noOpenGL=wxConfigBase::Get()->Read(wxT("DisableOpenGL"), 0l);
00306         disableOpenGL=(noOpenGL==1);
00307     };
00308 
00309     wxBitmap bitmap;
00310     HuginSplashScreen* splash = 0;
00311     wxYield();
00312 
00313     if (bitmap.LoadFile(huginApp::Get()->GetXRCPath() + wxT("data/splash.png"), wxBITMAP_TYPE_PNG))
00314     {
00315         // embed package version into string.
00316         {
00317             wxMemoryDC dc;
00318             dc.SelectObject(bitmap);
00319 #ifdef __WXMAC__
00320             wxFont font(9, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
00321 #else
00322             wxFont font(8, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
00323 #endif
00324             dc.SetFont(font);
00325             dc.SetTextForeground(*wxBLACK);
00326             dc.SetTextBackground(*wxWHITE);
00327             int tw, th;
00328             wxString version;
00329             version.Printf(_("Version %s"), wxString(hugin_utils::GetHuginVersion().c_str(), wxConvLocal).c_str());
00330             dc.GetTextExtent(version, &tw, &th);
00331             // place text on bitmap.
00332             dc.DrawText(version, bitmap.GetWidth() - tw - 3, bitmap.GetHeight() - th - 3);
00333         }
00334 
00335         splash = new HuginSplashScreen(NULL, bitmap);
00336     } else {
00337         wxLogFatalError(_("Fatal installation error\nThe file data/splash.png was not found at:") + huginApp::Get()->GetXRCPath());
00338         abort();
00339     }
00340     //splash->Refresh();
00341     wxYield();
00342 
00343     // save our pointer
00344     m_this = this;
00345 
00346     DEBUG_TRACE("");
00347     // load our children. some children might need special
00348     // initialization. this will be done later.
00349     wxXmlResource::Get()->LoadFrame(this, parent, wxT("main_frame"));
00350     DEBUG_TRACE("");
00351 
00352     // load our menu bar
00353 #ifdef __WXMAC__
00354     wxApp::s_macAboutMenuItemId = XRCID("action_show_about");
00355     wxApp::s_macPreferencesMenuItemId = XRCID("action_show_prefs");
00356     wxApp::s_macExitMenuItemId = XRCID("action_exit_hugin");
00357     wxApp::s_macHelpMenuTitleName = _("&Help");
00358 #endif
00359     wxMenuBar* mainMenu=wxXmlResource::Get()->LoadMenuBar(this, wxT("main_menubar"));
00360     m_menu_file_simple=wxXmlResource::Get()->LoadMenu(wxT("file_menu_simple"));
00361     m_menu_file_advanced=wxXmlResource::Get()->LoadMenu(wxT("file_menu_advanced"));
00362     mainMenu->Insert(0, m_menu_file_simple, _("&File"));
00363     SetMenuBar(mainMenu);
00364     SetOptimizeOnlyActiveImages(m_optOnlyActiveImages);
00365 
00366 #ifdef HUGIN_HSI
00367     wxMenuBar* menubar=GetMenuBar();
00368     // the plugin menu will be generated dynamically
00369     wxMenu *pluginMenu=new wxMenu();
00370     // search for all .py files in plugins directory
00371     wxDir dir(GetDataPath()+wxT("plugins"));
00372     if (dir.IsOpened())
00373     {
00374         wxString filename;
00375         bool cont = dir.GetFirst(&filename, wxT("*.py"), wxDIR_FILES | wxDIR_HIDDEN);
00376         PluginItems items;
00377         while (cont)
00378         {
00379             wxFileName file(dir.GetName(), filename);
00380             file.MakeAbsolute();
00381             PluginItem item(file);
00382             if (item.IsAPIValid())
00383             {
00384                 items.push_back(item);
00385             };
00386             cont = dir.GetNext(&filename);
00387         };
00388         items.sort(comparePluginItem);
00389 
00390         int pluginID = wxID_HIGHEST + 2000;
00391         for (PluginItems::const_iterator it = items.begin(); it != items.end(); ++it)
00392         {
00393             PluginItem item = *it;
00394             int categoryID = pluginMenu->FindItem(item.GetCategory());
00395             wxMenu* categoryMenu;
00396             if (categoryID == wxNOT_FOUND)
00397             {
00398                 categoryMenu = new wxMenu();
00399                 pluginMenu->AppendSubMenu(categoryMenu, item.GetCategory());
00400             }
00401             else
00402             {
00403                 categoryMenu = pluginMenu->FindItem(categoryID)->GetSubMenu();
00404             };
00405             categoryMenu->Append(pluginID, item.GetName(), item.GetDescription());
00406             m_plugins[pluginID] = item.GetFilename();
00407             Connect(pluginID, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainFrame::OnPlugin));
00408             pluginID++;
00409         };
00410         // show the new menu
00411         if (pluginMenu->GetMenuItemCount() > 0)
00412         {
00413             menubar->Insert(menubar->GetMenuCount() - 2, pluginMenu, _("&Actions"));
00414         };
00415     };
00416 #else
00417     GetMenuBar()->Enable(XRCID("action_python_script"), false);
00418 #endif
00419 
00420     // create tool bar
00421     SetToolBar(wxXmlResource::Get()->LoadToolBar(this, wxT("main_toolbar")));
00422 
00423     // Disable tools by default
00424     enableTools(false);
00425 
00426     // put an "unknown" object in an xrc file and
00427     // take as wxObject (second argument) the return value of wxXmlResource::Get
00428     // finish the images_panel
00429     DEBUG_TRACE("");
00430 
00431     // image_panel
00432     images_panel = XRCCTRL(*this, "images_panel_unknown", ImagesPanel);
00433     assert(images_panel);
00434     images_panel->Init(&pano);
00435     DEBUG_TRACE("");
00436 
00437     m_notebook = XRCCTRL((*this), "controls_notebook", wxNotebook);
00438 //    m_notebook = ((wxNotebook*) ((*this).FindWindow(XRCID("controls_notebook"))));
00439 //    m_notebook = ((wxNotebook*) (FindWindow(XRCID("controls_notebook"))));
00440     DEBUG_ASSERT(m_notebook);
00441 
00442     // the mask panel
00443     mask_panel = XRCCTRL(*this, "mask_panel_unknown", MaskEditorPanel);
00444     assert(mask_panel);
00445     mask_panel->Init(&pano);
00446 
00447     // the pano_panel
00448     DEBUG_TRACE("");
00449     pano_panel = XRCCTRL(*this, "panorama_panel_unknown", PanoPanel);
00450     assert(pano_panel);
00451     pano_panel->Init(&pano);
00452     pano_panel->panoramaChanged (pano); // initialize from pano
00453 
00454     cpe = XRCCTRL(*this, "cp_editor_panel_unknown", CPEditorPanel);
00455     assert(cpe);
00456     cpe->Init(&pano);
00457 
00458     opt_panel = XRCCTRL(*this, "optimizer_panel_unknown", OptimizePanel);
00459     assert(opt_panel);
00460     opt_panel->Init(&pano);
00461     m_show_opt_panel=true;
00462 
00463     opt_photo_panel = XRCCTRL(*this, "optimizer_photometric_panel_unknown", OptimizePhotometricPanel);
00464     assert(opt_photo_panel);
00465     opt_photo_panel->Init(&pano);
00466     m_show_opt_photo_panel=true;
00467 
00468     // generate list of most recently uses files and add it to menu
00469     // needs to be initialized before the fast preview, there we call AddFilesToMenu()
00470     wxConfigBase * config=wxConfigBase::Get();
00471     m_mruFiles.Load(*config);
00472     m_mruFiles.UseMenu(m_menu_file_advanced->FindItem(XRCID("menu_mru"))->GetSubMenu());
00473 
00474     preview_frame = new PreviewFrame(this, pano);
00475     if(disableOpenGL)
00476     {
00477         gl_preview_frame=NULL;
00478         DisableOpenGLTools();
00479         m_mruFiles.AddFilesToMenu();
00480     }
00481     else
00482     {
00483         gl_preview_frame = new GLPreviewFrame(this, pano);
00484     };
00485 
00486     // set the minimize icon
00487 #ifdef __WXMSW__
00488     wxIcon myIcon(GetXRCPath() + wxT("data/hugin.ico"),wxBITMAP_TYPE_ICO);
00489 #else
00490     wxIcon myIcon(GetXRCPath() + wxT("data/hugin.png"),wxBITMAP_TYPE_PNG);
00491 #endif
00492     SetIcon(myIcon);
00493 
00494     // create a new drop handler. wxwindows deletes the automaticall
00495     SetDropTarget(new PanoDropTarget(pano));
00496     DEBUG_TRACE("");
00497 
00498     PanoOperation::GeneratePanoOperationVector();
00499 
00500     // create a status bar
00501     const int fields (2);
00502     CreateStatusBar(fields);
00503     int widths[fields] = {-1, 85};
00504     SetStatusWidths( fields, &widths[0]);
00505     SetStatusText(_("Started"), 0);
00506     wxYield();
00507     DEBUG_TRACE("");
00508 
00509     // observe the panorama
00510     pano.addObserver(this);
00511 
00512     // Set sizing characteristics
00513     //set minumum size
00514 #if defined __WXMAC__ || defined __WXMSW__
00515     // a minimum nice looking size; smaller than this would clutter the layout.
00516     SetSizeHints(900, 675);
00517 #else
00518     // For ASUS eeePc
00519     SetSizeHints(780, 455); //set minumum size
00520 #endif
00521 
00522     // set progress display for image cache.
00523     ImageCache::getInstance().setProgressDisplay(this);
00524 #if defined __WXMSW__
00525     unsigned long long mem = HUGIN_IMGCACHE_UPPERBOUND;
00526     unsigned long mem_low = wxConfigBase::Get()->Read(wxT("/ImageCache/UpperBound"), HUGIN_IMGCACHE_UPPERBOUND);
00527     unsigned long mem_high = wxConfigBase::Get()->Read(wxT("/ImageCache/UpperBoundHigh"), (long) 0);
00528     if (mem_high > 0) {
00529       mem = ((unsigned long long) mem_high << 32) + mem_low;
00530     }
00531     else {
00532       mem = mem_low;
00533     }
00534     ImageCache::getInstance().SetUpperLimit(mem);
00535 #else
00536     ImageCache::getInstance().SetUpperLimit(wxConfigBase::Get()->Read(wxT("/ImageCache/UpperBound"), HUGIN_IMGCACHE_UPPERBOUND));
00537 #endif
00538 
00539     if(splash) {
00540         splash->Close();
00541         delete splash;
00542     }
00543     wxYield();
00544 
00545     // disable automatic Layout() calls, to it by hand
00546     SetAutoLayout(false);
00547 
00548 
00549 #ifdef __WXMSW__
00550     // wxFrame does have a strange background color on Windows, copy color from a child widget
00551     this->SetBackgroundColour(images_panel->GetBackgroundColour());
00552 #endif
00553 
00554 // By using /SUBSYSTEM:CONSOLE /ENTRY:"WinMainCRTStartup" in the linker
00555 // options for the debug build, a console window will be used for stdout
00556 // and stderr. No need to redirect to a file. Better security since we can't
00557 // guarantee that c: exists and writing a file to the root directory is
00558 // never a good idea. release build still uses /SUBSYSTEM:WINDOWS
00559 
00560 #if 0
00561 #ifdef DEBUG
00562 #ifdef __WXMSW__
00563 
00564     freopen("c:\\hugin_stdout.txt", "w", stdout);    // redirect stdout to file
00565     freopen("c:\\hugin_stderr.txt", "w", stderr);    // redirect stderr to file
00566 #endif
00567 #endif
00568 #endif
00569     //reload gui level
00570     long guiLevel=config->Read(wxT("/GuiLevel"),(long)0);
00571     guiLevel = std::max<long>(0, std::min<long>(2, guiLevel));
00572     if(guiLevel==GUI_SIMPLE && disableOpenGL)
00573     {
00574         guiLevel=GUI_ADVANCED;
00575     };
00576     SetGuiLevel((GuiLevel)guiLevel);
00577 
00578     DEBUG_TRACE("");
00579 #ifdef __WXGTK__
00580     // set explicit focus to assistant panel for better processing key presses
00581     images_panel->SetFocus();
00582 #endif
00583 }
00584 
00585 MainFrame::~MainFrame()
00586 {
00587     DEBUG_TRACE("dtor");
00588     if(m_guiLevel==GUI_SIMPLE)
00589     {
00590         delete m_menu_file_advanced;
00591     }
00592     else
00593     {
00594         delete m_menu_file_simple;
00595     };
00596     ImageCache::getInstance().setProgressDisplay(NULL);
00597         delete & ImageCache::getInstance();
00598     delete & PanoCommand::GlobalCmdHist::getInstance();
00599 //    delete cpe;
00600 //    delete images_panel;
00601     DEBUG_DEBUG("removing observer");
00602     pano.removeObserver(this);
00603 
00604     // get the global config object
00605     wxConfigBase* config = wxConfigBase::Get();
00606 
00607     StoreFramePosition(this, wxT("MainFrame"));
00608 
00609     //store most recently used files
00610     m_mruFiles.Save(*config);
00611     //store gui level
00612     config->Write(wxT("/GuiLevel"),(long)m_guiLevel);
00613     config->Flush();
00614     if(svmModel!=NULL)
00615     {
00616         celeste::destroySVMmodel(svmModel);
00617     };
00618     PanoOperation::CleanPanoOperationVector();
00619 
00620     DEBUG_TRACE("dtor end");
00621 }
00622 
00623 void MainFrame::panoramaChanged(HuginBase::Panorama &pano)
00624 {
00625     wxToolBar* theToolBar = GetToolBar();
00626     wxMenuBar* theMenuBar = GetMenuBar();
00627     bool can_undo = PanoCommand::GlobalCmdHist::getInstance().canUndo();
00628     theMenuBar->Enable    (XRCID("ID_EDITUNDO"), can_undo);
00629     theToolBar->EnableTool(XRCID("ID_EDITUNDO"), can_undo);
00630     bool can_redo = PanoCommand::GlobalCmdHist::getInstance().canRedo();
00631     theMenuBar->Enable    (XRCID("ID_EDITREDO"), can_redo);
00632     theToolBar->EnableTool(XRCID("ID_EDITREDO"), can_redo);
00633 
00634     //show or hide optimizer and exposure optimizer tab depending on optimizer master switches
00635     if(pano.getOptimizerSwitch()==0 && !m_show_opt_panel)
00636     {
00637         m_notebook->InsertPage(3, opt_panel, _("Optimizer"));
00638         m_show_opt_panel=true;
00639     };
00640     if(pano.getOptimizerSwitch()!=0 && m_show_opt_panel)
00641     {
00642         m_notebook->RemovePage(3);
00643         m_show_opt_panel=false;
00644     };
00645     if(pano.getPhotometricOptimizerSwitch()==0 && !m_show_opt_photo_panel)
00646     {
00647         if(m_show_opt_panel)
00648         {
00649             m_notebook->InsertPage(4, opt_photo_panel, _("Exposure"));
00650         }
00651         else
00652         {
00653             m_notebook->InsertPage(3, opt_photo_panel, _("Exposure"));
00654         }
00655         m_show_opt_photo_panel=true;
00656     };
00657     if(pano.getPhotometricOptimizerSwitch()!=0 && m_show_opt_photo_panel)
00658     {
00659         if(m_show_opt_panel)
00660         {
00661             m_notebook->RemovePage(4);
00662         }
00663         else
00664         {
00665             m_notebook->RemovePage(3);
00666         };
00667         m_show_opt_photo_panel=false;
00668     };
00669     theMenuBar->Enable(XRCID("ID_SHOW_PANEL_OPTIMIZER"), m_show_opt_panel);
00670     theMenuBar->Enable(XRCID("ID_SHOW_PANEL_OPTIMIZER_PHOTOMETRIC"), m_show_opt_photo_panel);
00671 }
00672 
00673 //void MainFrame::panoramaChanged(HuginBase::Panorama &panorama)
00674 void MainFrame::panoramaImagesChanged(HuginBase::Panorama &panorama, const HuginBase::UIntSet & changed)
00675 {
00676     DEBUG_TRACE("");
00677     assert(&pano == &panorama);
00678     if (pano.getNrOfImages() == 0) {
00679           enableTools(false);
00680         } else {
00681           enableTools(true);
00682         }
00683     GetMenuBar()->Enable(XRCID("action_assistant"), pano.getNrOfImages()>=2);
00684     GetMenuBar()->Enable(XRCID("action_batch_assistant"), pano.getNrOfImages()>=2);
00685 }
00686 
00687 void MainFrame::OnUserQuit(wxCommandEvent & e)
00688 {
00689     Close();
00690 }
00691 
00692 bool MainFrame::CloseProject(bool cancelable)
00693 {
00694     if (pano.isDirty()) {
00695         wxMessageDialog message(wxGetActiveWindow(),
00696                                 _("Save changes to the panorama before closing?"),
00697 #ifdef _WIN32
00698                                 _("Hugin"),
00699 #else
00700                                 wxT(""),
00701 #endif
00702                                 wxICON_EXCLAMATION | wxYES_NO | (cancelable? (wxCANCEL):0));
00703 #if wxCHECK_VERSION(2, 9, 0)
00704     message.SetExtendedMessage(_("If you close without saving, changes since your last save will be discarded"));
00705     #if defined __WXMAC__ || defined __WXMSW__
00706         // Apple human interface guidelines and Windows user experience interaction guidelines
00707         message.SetYesNoLabels(wxID_SAVE, _("Don't Save"));
00708     #else
00709         // Gnome human interface guidelines:
00710         message.SetYesNoLabels(wxID_SAVE, _("Close without saving"));
00711     #endif
00712 #endif
00713         int answer = message.ShowModal();
00714         switch (answer){
00715             case wxID_YES:
00716             {
00717                 wxCommandEvent dummy;
00718                 OnSaveProject(dummy);
00719                 return !pano.isDirty();
00720             }
00721             case wxID_CANCEL:
00722                 return false;
00723             default: //no save
00724                 return true;
00725         }
00726     }
00727     else return true;
00728 }
00729 
00730 void MainFrame::OnExit(wxCloseEvent & e)
00731 {
00732     DEBUG_TRACE("");
00733     if(m_guiLevel!=GUI_SIMPLE)
00734     {
00735         if(!CloseProject(e.CanVeto()))
00736         {
00737            if (e.CanVeto())
00738            {
00739                 e.Veto();
00740                 return;
00741            }
00742            wxLogError(_("forced close"));
00743         }
00744     }
00745     else
00746     {
00747         if(e.CanVeto())
00748         {
00749             Hide();
00750             e.Veto();
00751             return;
00752         };
00753     };
00754 
00755     if(preview_frame)
00756     {
00757        preview_frame->Close(true);
00758     }
00759 
00760     ImageCache::getInstance().flush();
00761     Destroy();
00762     DEBUG_TRACE("");
00763 }
00764 
00765 void MainFrame::OnSaveProject(wxCommandEvent & e)
00766 {
00767     DEBUG_TRACE("");
00768     try {
00769     wxFileName scriptName = m_filename;
00770     if (m_filename == wxT("")) {
00771         OnSaveProjectAs(e);
00772         scriptName = m_filename;
00773     } else {
00774         // the project file is just a PTOptimizer script...
00775         std::string path = hugin_utils::getPathPrefix(std::string(scriptName.GetFullPath().mb_str(HUGIN_CONV_FILENAME)));
00776         DEBUG_DEBUG("stripping " << path << " from image filenames");
00777         std::ofstream script(scriptName.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
00778         script.exceptions ( std::ofstream::eofbit | std::ofstream::failbit | std::ofstream::badbit );
00779         HuginBase::UIntSet all;
00780         if (pano.getNrOfImages() > 0) {
00781            fill_set(all, 0, pano.getNrOfImages()-1);
00782         }
00783         pano.printPanoramaScript(script, pano.getOptimizeVector(), pano.getOptions(), all, false, path);
00784         script.close();
00785 
00786         SetStatusText(wxString::Format(_("saved project %s"), m_filename.c_str()),0);
00787         if(m_guiLevel==GUI_SIMPLE)
00788         {
00789             if(gl_preview_frame)
00790             {
00791                 gl_preview_frame->SetTitle(scriptName.GetName() + wxT(".") + scriptName.GetExt() + wxT(" - ") + _("Hugin - Panorama Stitcher"));
00792             };
00793             SetTitle(scriptName.GetName() + wxT(".") + scriptName.GetExt() + wxT(" - ") + _("Panorama editor"));
00794         }
00795         else
00796         {
00797             SetTitle(scriptName.GetName() + wxT(".") + scriptName.GetExt() + wxT(" - ") + _("Hugin - Panorama Stitcher"));
00798         };
00799 
00800         pano.clearDirty();
00801     }
00802     } catch (std::exception & e) {
00803         wxString err(e.what(), wxConvLocal);
00804             wxMessageBox(wxString::Format(_("Could not save project file \"%s\".\nMaybe the file or the folder is read-only.\n\n(Error code: %s)"),m_filename.c_str(),err.c_str()),_("Error"),wxOK|wxICON_ERROR);
00805     }
00806 }
00807 
00808 void MainFrame::OnSaveProjectAs(wxCommandEvent & e)
00809 {
00810     DEBUG_TRACE("");
00811     wxFileName scriptName;
00812     if (m_filename.IsEmpty())
00813     {
00814         scriptName.Assign(getDefaultProjectName(pano) + wxT(".pto"));
00815     }
00816     else
00817     {
00818         scriptName=m_filename;
00819     };
00820     scriptName.Normalize();
00821     wxFileDialog dlg(wxGetActiveWindow(),
00822                      _("Save project file"),
00823                      scriptName.GetPath(), scriptName.GetFullName(),
00824                      _("Project files (*.pto)|*.pto|All files (*)|*"),
00825                      wxFD_SAVE | wxFD_OVERWRITE_PROMPT, wxDefaultPosition);
00826     if (dlg.ShowModal() == wxID_OK) {
00827         wxConfig::Get()->Write(wxT("/actualPath"), dlg.GetDirectory());  // remember for later
00828         wxString fn = dlg.GetPath();
00829         if (fn.Right(4).CmpNoCase(wxT(".pto"))!=0)
00830         {
00831             fn.Append(wxT(".pto"));
00832             if (wxFile::Exists(fn)) {
00833                 int d = wxMessageBox(wxString::Format(_("File %s exists. Overwrite?"), fn.c_str()),
00834                     _("Save project"), wxYES_NO | wxICON_QUESTION);
00835                 if (d != wxYES) {
00836                     return;
00837                 }
00838             }
00839         }
00840         m_filename = fn;
00841         m_mruFiles.AddFileToHistory(m_filename);
00842         OnSaveProject(e);
00843     }
00844 }
00845 
00846 void MainFrame::OnSavePTStitcherAs(wxCommandEvent & e)
00847 {
00848     DEBUG_TRACE("");
00849     wxString scriptName = m_filename;
00850     if (m_filename == wxT("")) {
00851         scriptName = getDefaultProjectName(pano);
00852     }
00853     wxFileName scriptNameFN(scriptName);
00854     wxString fn = scriptNameFN.GetName() + wxT(".txt");
00855     wxFileDialog dlg(wxGetActiveWindow(),
00856                      _("Save PTmender script file"),
00857                      wxConfigBase::Get()->Read(wxT("/actualPath"),wxT("")), fn,
00858                      _("PTmender files (*.txt)|*.txt"),
00859                      wxFD_SAVE | wxFD_OVERWRITE_PROMPT, wxDefaultPosition);
00860     if (dlg.ShowModal() == wxID_OK) {
00861         wxString fname = dlg.GetPath();
00862         // the project file is just a PTStitcher script...
00863         wxFileName scriptName = fname;
00864         HuginBase::UIntSet all;
00865         if (pano.getNrOfImages() > 0) {
00866             fill_set(all, 0, pano.getNrOfImages()-1);
00867         }
00868         std::ofstream script(scriptName.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
00869         pano.printStitcherScript(script, pano.getOptions(), all);
00870         script.close();
00871     }
00872 
00873 }
00874 
00875 void MainFrame::LoadProjectFile(const wxString & filename)
00876 {
00877     DEBUG_TRACE("");
00878     m_filename = filename;
00879 
00880     // remove old images from cache
00881     // hmm probably not a good idea, if the project is reloaded..
00882     // ImageCache::getInstance().flush();
00883 
00884     SetStatusText( _("Open project:   ") + filename);
00885 
00886     wxFileName fname(filename);
00887     wxString path = fname.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
00888     if (fname.IsOk() && fname.FileExists()) {
00889         wxBusyCursor wait;
00890         deregisterPTWXDlgFcn();
00891         PanoCommand::GlobalCmdHist::getInstance().addCommand(
00892             new PanoCommand::wxLoadPTProjectCmd(pano, (const char *)filename.mb_str(HUGIN_CONV_FILENAME), (const char *)path.mb_str(HUGIN_CONV_FILENAME), true)
00893            );
00894         PanoCommand::GlobalCmdHist::getInstance().clear();
00895         registerPTWXDlgFcn();
00896         DEBUG_DEBUG("project contains " << pano.getNrOfImages() << " after load");
00897         GuiLevel reqGuiLevel=GetMinimumGuiLevel(pano);
00898         if(reqGuiLevel>m_guiLevel)
00899         {
00900             SetGuiLevel(reqGuiLevel);
00901         };
00902         SetStatusText(_("Project opened"));
00903         m_mruFiles.AddFileToHistory(fname.GetFullPath());
00904         if(m_guiLevel==GUI_SIMPLE)
00905         {
00906             if(gl_preview_frame)
00907             {
00908                 gl_preview_frame->SetTitle(fname.GetName() + wxT(".") + fname.GetExt() + wxT(" - ") + _("Hugin - Panorama Stitcher"));
00909             };
00910             SetTitle(fname.GetName() + wxT(".") + fname.GetExt() + wxT(" - ") + _("Panorama editor"));
00911         }
00912         else
00913         {
00914             SetTitle(fname.GetName() + wxT(".") + fname.GetExt() + wxT(" - ") + _("Hugin - Panorama Stitcher"));
00915         };
00916         if (! (fname.GetExt() == wxT("pto"))) {
00917             // do not remember filename if its not a hugin project
00918             // to avoid overwriting the original project with an
00919             // incompatible one
00920             m_filename = wxT("");
00921         }
00922         // get the global config object
00923         wxConfigBase* config = wxConfigBase::Get();
00924         config->Write(wxT("/actualPath"), path);  // remember for later
00925     } else {
00926         SetStatusText( _("Error opening project:   ") + filename);
00927         DEBUG_ERROR("Could not open file " << filename);
00928     }
00929 
00930     // force update of preview window
00931     if ( !(preview_frame->IsIconized() ||(! preview_frame->IsShown()) ) ) {
00932         wxCommandEvent dummy;
00933         preview_frame->OnUpdate(dummy);
00934     }
00935 }
00936 
00937 #ifdef __WXMAC__
00938 void MainFrame::MacOnOpenFile(const wxString & filename)
00939 {
00940     if(!CloseProject(true)) return; //if closing old project is canceled do nothing.
00941 
00942     ImageCache::getInstance().flush();
00943     LoadProjectFile(filename);
00944 }
00945 #endif
00946 
00947 void MainFrame::OnLoadProject(wxCommandEvent & e)
00948 {
00949     DEBUG_TRACE("");
00950 
00951     if(CloseProject(true)) //if closing old project is canceled do nothing.
00952     {
00953         // get the global config object
00954         wxConfigBase* config = wxConfigBase::Get();
00955 
00956         wxString defaultdir = config->Read(wxT("/actualPath"),wxT(""));
00957         wxFileDialog dlg(wxGetActiveWindow(),
00958                          _("Open project file"),
00959                          defaultdir, wxT(""),
00960                          _("Project files (*.pto)|*.pto|All files (*)|*"),
00961                          wxFD_OPEN, wxDefaultPosition);
00962         dlg.SetDirectory(defaultdir);
00963         if (dlg.ShowModal() == wxID_OK)
00964         {
00965             wxString filename = dlg.GetPath();
00966             if(vigra::isImage(filename.mb_str(HUGIN_CONV_FILENAME)))
00967             {
00968                 if(wxMessageBox(wxString::Format(_("File %s is an image file and not a project file.\nThis file can't be open with File, Open.\nDo you want to add this image file to the current project?"),filename.c_str()),
00969 #ifdef __WXMSW__
00970                     _("Hugin"),
00971 #else
00972                     wxT(""),
00973 #endif
00974                     wxYES_NO | wxICON_QUESTION)==wxYES)
00975                 {
00976                     wxArrayString filenameArray;
00977                     filenameArray.Add(filename);
00978                     AddImages(filenameArray);
00979                 };
00980                 return;
00981             }
00982             else
00983             {
00984                 // remove old images from cache
00985                 ImageCache::getInstance().flush();
00986 
00987                 LoadProjectFile(filename);
00988                 return;
00989             };
00990         }
00991     }
00992     // do not close old project
00993     // nothing to open
00994     SetStatusText( _("Open project: cancel"));
00995 }
00996 
00997 void MainFrame::OnNewProject(wxCommandEvent & e)
00998 {
00999     if(!CloseProject(true)) return; //if closing current project is canceled
01000 
01001     m_filename = wxT("");
01002     PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::wxNewProjectCmd(pano));
01003     PanoCommand::GlobalCmdHist::getInstance().clear();
01004     // remove old images from cache
01005     ImageCache::getInstance().flush();
01006     if(m_guiLevel==GUI_SIMPLE)
01007     {
01008         if(gl_preview_frame)
01009         {
01010             gl_preview_frame->SetTitle(_("Hugin - Panorama Stitcher"));
01011         };
01012         SetTitle(_("Panorama editor"));
01013     }
01014     else
01015     {
01016         SetTitle(_("Hugin - Panorama Stitcher"));
01017     };
01018 
01019     wxCommandEvent dummy;
01020     preview_frame->OnUpdate(dummy);
01021 }
01022 
01023 void MainFrame::OnAddImages( wxCommandEvent& event )
01024 {
01025     DEBUG_TRACE("");
01026     PanoOperation::AddImageOperation addImage;
01027     HuginBase::UIntSet images;
01028     PanoCommand::PanoCommand* cmd = addImage.GetCommand(wxGetActiveWindow(), pano, images, m_guiLevel);
01029     if(cmd!=NULL)
01030     {
01031         PanoCommand::GlobalCmdHist::getInstance().addCommand(cmd);
01032     }
01033     else
01034     {
01035         // nothing to open
01036         SetStatusText( _("Add Image: cancel"));
01037     }
01038 
01039     DEBUG_TRACE("");
01040 }
01041 
01042 void MainFrame::AddImages(wxArrayString& filenameArray)
01043 {
01044     wxArrayString invalidFiles;
01045     for(unsigned int i=0;i<filenameArray.GetCount(); i++)
01046     {
01047         if(containsInvalidCharacters(filenameArray[i]))
01048         {
01049             invalidFiles.Add(filenameArray[i]);
01050         };
01051     };
01052     if(invalidFiles.size()>0)
01053     {
01054         ShowFilenameWarning(this, invalidFiles);
01055     }
01056     else
01057     {
01058         std::vector<std::string> filesv;
01059         for (unsigned int i=0; i< filenameArray.GetCount(); i++) {
01060             filesv.push_back((const char *)filenameArray[i].mb_str(HUGIN_CONV_FILENAME));
01061         }
01062 
01063         // we got some images to add.
01064         if (filesv.size() > 0) {
01065             // use a Command to ensure proper undo and updating of GUI
01066             // parts
01067             wxBusyCursor();
01068             PanoCommand::GlobalCmdHist::getInstance().addCommand(
01069                 new PanoCommand::wxAddImagesCmd(pano, filesv)
01070                 );
01071         };
01072     };
01073 };
01074 
01075 void MainFrame::OnAddTimeImages( wxCommandEvent& event )
01076 {
01077     PanoOperation::AddImagesSeriesOperation imageSeriesOp;
01078     HuginBase::UIntSet images;
01079     PanoCommand::PanoCommand* cmd = imageSeriesOp.GetCommand(wxGetActiveWindow(), pano, images, m_guiLevel);
01080     if(cmd!=NULL)
01081     {
01082         PanoCommand::GlobalCmdHist::getInstance().addCommand(cmd);
01083     };
01084 };
01085 
01086 void MainFrame::OnShowDonate(wxCommandEvent & e)
01087 {
01088     wxLaunchDefaultBrowser(wxT("http://sourceforge.net/project/project_donations.php?group_id=77506"));
01089 }
01090 
01091 
01092 void MainFrame::OnShowPanel(wxCommandEvent & e)
01093 {
01094     if(e.GetId()==XRCID("ID_SHOW_PANEL_MASK"))
01095         m_notebook->SetSelection(1);
01096     else
01097         if(e.GetId()==XRCID("ID_SHOW_PANEL_CP_EDITOR"))
01098             m_notebook->SetSelection(2);
01099         else
01100             if(e.GetId()==XRCID("ID_SHOW_PANEL_OPTIMIZER"))
01101                 m_notebook->SetSelection(3);
01102             else
01103                 if(e.GetId()==XRCID("ID_SHOW_PANEL_OPTIMIZER_PHOTOMETRIC"))
01104                 {
01105                     if(m_show_opt_panel)
01106                     {
01107                         m_notebook->SetSelection(4);
01108                     }
01109                     else
01110                     {
01111                         m_notebook->SetSelection(3);
01112                     };
01113                 }
01114                 else
01115                     if(e.GetId()==XRCID("ID_SHOW_PANEL_PANORAMA"))
01116                     {
01117                         if(m_show_opt_panel && m_show_opt_photo_panel)
01118                         {
01119                             m_notebook->SetSelection(5);
01120                         }
01121                         else
01122                         {
01123                             if(m_show_opt_panel || m_show_opt_photo_panel)
01124                             {
01125                                 m_notebook->SetSelection(4);
01126                             }
01127                             else
01128                             {
01129                                 m_notebook->SetSelection(3);
01130                             };
01131                         };
01132                     }
01133                     else
01134                         m_notebook->SetSelection(0);
01135 }
01136 
01137 
01138 void MainFrame::OnAbout(wxCommandEvent & e)
01139 {
01140     AboutDialog dlg(wxGetActiveWindow());
01141     dlg.ShowModal();
01142 }
01143 
01144 /*
01145 void MainFrame::OnAbout(wxCommandEvent & e)
01146 {
01147     DEBUG_TRACE("");
01148     wxDialog dlg;
01149         wxString strFile;
01150         wxString langCode;
01151 
01152     wxXmlResource::Get()->LoadDialog(&dlg, this, wxT("about_dlg"));
01153 
01154 #if __WXMAC__ && defined MAC_SELF_CONTAINED_BUNDLE
01155     //rely on the system's locale choice
01156     strFile = MacGetPathToBundledResourceFile(CFSTR("about.htm"));
01157     if(strFile!=wxT("")) XRCCTRL(dlg,"about_html",wxHtmlWindow)->LoadPage(strFile);
01158 #else
01159     //if the language is not default, load custom About file (if exists)
01160     langCode = huginApp::Get()->GetLocale().GetName().Left(2).Lower();
01161     DEBUG_INFO("Lang Code: " << langCode.mb_str(wxConvLocal));
01162     if(langCode != wxString(wxT("en")))
01163     {
01164         strFile = GetXRCPath() + wxT("data/about_") + langCode + wxT(".htm");
01165         if(wxFile::Exists(strFile))
01166         {
01167             DEBUG_TRACE("Using About: " << strFile.mb_str(wxConvLocal));
01168             XRCCTRL(dlg,"about_html",wxHtmlWindow)->LoadPage(strFile);
01169         }
01170     }
01171 #endif
01172     dlg.ShowModal();
01173 }
01174 */
01175 
01176 void MainFrame::OnHelp(wxCommandEvent & e)
01177 {
01178     DisplayHelp();
01179 }
01180 
01181 void MainFrame::OnKeyboardHelp(wxCommandEvent & e)
01182 {
01183     DisplayHelp(wxT("/Hugin_Keyboard_shortcuts.html"));
01184 }
01185 
01186 void MainFrame::OnFAQ(wxCommandEvent & e)
01187 {
01188     DisplayHelp(wxT("/Hugin_FAQ.html"));
01189 }
01190 
01191 
01192 void MainFrame::DisplayHelp(wxString section)
01193 {
01194     // TODO:
01195     // structure a frame with navigation on the left and content on the right
01196     // always load the same navigation on the left and the section into the frame
01197     // find a way to target always the same window rather than opening new window / tabs in the browser every time
01198     // make it look nicer with some CSS styling
01199 
01200     // section is the HTML document to be displayed, from inside the data folder
01201 
01202     DEBUG_TRACE("");
01203 
01204 #ifdef __WXMSW__
01205     if (section.IsEmpty())
01206     {
01207         // wxWidgets 3.x has a bug, that prevents DisplaySection to work on Win8/10 64 bit
01208         // see: http://trac.wxwidgets.org/ticket/14888
01209         // so using DisplayContents() and our own implementation of HuginCHMHelpController
01210         GetHelpController().DisplayContents();
01211     }
01212     else
01213     {
01214 #if wxCHECK_VERSION(3,1,1)
01215         GetHelpController().DisplaySection(section);
01216 #else
01217         GetHelpController().DisplayHelpPage(section);
01218 #endif
01219     };
01220 #else
01221     if (section.IsEmpty())
01222     {
01223         section = wxT("/Hugin.html");
01224     }
01225 #if defined __WXMAC__ && defined MAC_SELF_CONTAINED_BUNDLE
01226     // On Mac, xrc/data/help_LOCALE should be in the bundle as LOCALE.lproj/help
01227     // which we can rely on the operating sytem to pick the right locale's.
01228     wxString strFile = MacGetPathToBundledResourceFile(CFSTR("help"));
01229     if(strFile!=wxT(""))
01230     {
01231         strFile += section;
01232     } else {
01233         wxLogError(wxString::Format(wxT("Could not find help directory in the bundle"), strFile.c_str()));
01234         return;
01235     }
01236 #else
01237     // find base filename
01238     wxString helpFile = wxT("help_") + huginApp::Get()->GetLocale().GetCanonicalName() + section;
01239     DEBUG_INFO("help file candidate: " << helpFile.mb_str(wxConvLocal));
01240     //if the language is not default, load custom About file (if exists)
01241     wxString strFile = GetXRCPath() + wxT("data/") + helpFile;
01242     if(wxFile::Exists(strFile))
01243     {
01244         DEBUG_TRACE("Using About: " << strFile.mb_str(wxConvLocal));
01245     } else {
01246         strFile = GetXRCPath() + wxT("data/help_en_EN") + section;
01247     }
01248 #endif
01249     if(!wxFile::Exists(strFile))
01250     {
01251         wxLogError(wxString::Format(wxT("Could not open help file: %s"), strFile.c_str()));
01252         return;
01253     }
01254     DEBUG_INFO("help file: " << strFile.mb_str(wxConvLocal));
01255     if(!wxLaunchDefaultBrowser(strFile))
01256     {
01257         wxLogError(_("Can't start system's web browser"));
01258     }
01259 #endif
01260 }
01261 
01262 void MainFrame::OnTipOfDay(wxCommandEvent& WXUNUSED(e))
01263 {
01264     wxString strFile;
01265     bool bShowAtStartup;
01266 // DGSW FIXME - Unreferenced
01267 //      bool bTipsExist = false;
01268     int nValue;
01269 
01270     wxConfigBase * config = wxConfigBase::Get();
01271     nValue = config->Read(wxT("/MainFrame/ShowStartTip"),1l);
01272 
01273     //TODO: tips not localisable
01274     DEBUG_INFO("Tip index: " << nValue);
01275     strFile = GetXRCPath() + wxT("data/tips.txt");  //load default file
01276 
01277     DEBUG_INFO("Reading tips from " << strFile.mb_str(wxConvLocal));
01278     wxTipProvider *tipProvider = new LocalizedFileTipProvider(strFile, nValue);
01279     bShowAtStartup = wxShowTip(wxGetActiveWindow(), tipProvider, (nValue ? true : false));
01280 
01281     //store startup preferences
01282     nValue = (bShowAtStartup ? tipProvider->GetCurrentTip() : 0);
01283     DEBUG_INFO("Writing tip index: " << nValue);
01284     config->Write(wxT("/MainFrame/ShowStartTip"), nValue);
01285     delete tipProvider;
01286 }
01287 
01288 
01289 void MainFrame::OnShowPrefs(wxCommandEvent & e)
01290 {
01291     DEBUG_TRACE("");
01292     PreferencesDialog pref_dlg(wxGetActiveWindow());
01293     pref_dlg.ShowModal();
01294     //update image cache size
01295     wxConfigBase* cfg=wxConfigBase::Get();
01296 #if defined __WXMSW__
01297     unsigned long long mem = HUGIN_IMGCACHE_UPPERBOUND;
01298     unsigned long mem_low = cfg->Read(wxT("/ImageCache/UpperBound"), HUGIN_IMGCACHE_UPPERBOUND);
01299     unsigned long mem_high = cfg->Read(wxT("/ImageCache/UpperBoundHigh"), (long) 0);
01300     if (mem_high > 0)
01301     {
01302       mem = ((unsigned long long) mem_high << 32) + mem_low;
01303     }
01304     else
01305     {
01306       mem = mem_low;
01307     }
01308     ImageCache::getInstance().SetUpperLimit(mem);
01309 #else
01310     ImageCache::getInstance().SetUpperLimit(cfg->Read(wxT("/ImageCache/UpperBound"), HUGIN_IMGCACHE_UPPERBOUND));
01311 #endif
01312     images_panel->ReloadCPDetectorSettings();
01313     if(gl_preview_frame)
01314     {
01315         gl_preview_frame->SetShowProjectionHints(cfg->Read(wxT("/GLPreviewFrame/ShowProjectionHints"),HUGIN_SHOW_PROJECTION_HINTS)!=0);
01316     };
01317 }
01318 
01319 void MainFrame::UpdatePanels( wxCommandEvent& WXUNUSED(event) )
01320 {   // Maybe this can be invoced by the Panorama::Changed() or
01321     // something like this. So no everytime update would be needed.
01322     DEBUG_TRACE("");
01323 }
01324 
01325 void MainFrame::OnTogglePreviewFrame(wxCommandEvent & e)
01326 {
01327     DEBUG_TRACE("");
01328     if (preview_frame->IsIconized()) {
01329         preview_frame->Iconize(false);
01330     }
01331     preview_frame->Show();
01332     preview_frame->Raise();
01333 
01334         // we need to force an update since autoupdate fires
01335         // before the preview frame is shown
01336     wxCommandEvent dummy;
01337         preview_frame->OnUpdate(dummy);
01338 }
01339 
01340 void MainFrame::OnToggleGLPreviewFrame(wxCommandEvent & e)
01341 {
01342     if(gl_preview_frame==NULL)
01343     {
01344         return;
01345     };
01346 #if defined __WXMSW__ || defined __WXMAC__
01347     gl_preview_frame->InitPreviews();
01348 #endif
01349     if (gl_preview_frame->IsIconized()) {
01350         gl_preview_frame->Iconize(false);
01351     }
01352     gl_preview_frame->Show();
01353 #if defined __WXMSW__
01354     // on wxMSW Show() does not send OnShowEvent needed to update the
01355     // visibility state of the fast preview windows
01356     // so explicit calling this event handler
01357     wxShowEvent se;
01358     se.SetShow(true);
01359     gl_preview_frame->OnShowEvent(se);
01360 #elif defined __WXGTK__
01361     gl_preview_frame->LoadOpenGLLayout();
01362 #endif
01363     gl_preview_frame->Raise();
01364 }
01365 
01366 void MainFrame::OnShowCPFrame(wxCommandEvent & e)
01367 {
01368     DEBUG_TRACE("");
01369     if (cp_frame) {
01370         if (cp_frame->IsIconized()) {
01371             cp_frame->Iconize(false);
01372         }
01373         cp_frame->Show();
01374         cp_frame->Raise();
01375     } else {
01376         cp_frame = new CPListFrame(this, pano);
01377         cp_frame->Show();
01378     }
01379 }
01380 
01381 void MainFrame::OnCPListFrameClosed()
01382 {
01383     cp_frame = 0;
01384 }
01385 
01386 void MainFrame::OnOptimize(wxCommandEvent & e)
01387 {
01388     DEBUG_TRACE("");
01389     wxCommandEvent dummy;
01390     opt_panel->OnOptimizeButton(dummy);
01391 }
01392 
01393 void MainFrame::OnOnlyActiveImages(wxCommandEvent &e)
01394 {
01395     m_optOnlyActiveImages = GetMenuBar()->IsChecked(XRCID("action_optimize_only_active"));
01396     opt_panel->SetOnlyActiveImages(m_optOnlyActiveImages);
01397     // notify all observer so they can update their display
01398     pano.changeFinished();
01399 };
01400 
01401 void MainFrame::SetOptimizeOnlyActiveImages(const bool onlyActive)
01402 {
01403     m_optOnlyActiveImages = onlyActive;
01404     wxMenuBar* menubar = GetMenuBar();
01405     if (menubar)
01406     {
01407         menubar->Check(XRCID("action_optimize_only_active"), onlyActive);
01408         // notify all observer so they can update their display
01409         pano.changeFinished();
01410     };
01411 };
01412 
01413 const bool MainFrame::GetOptimizeOnlyActiveImages() const
01414 {
01415     return m_optOnlyActiveImages;
01416 };
01417 
01418 void MainFrame::OnPhotometricOptimize(wxCommandEvent & e)
01419 {
01420     wxCommandEvent dummy;
01421     opt_photo_panel->OnOptimizeButton(dummy);
01422 };
01423 
01424 void MainFrame::OnDoStitch(wxCommandEvent & e)
01425 {
01426     DEBUG_TRACE("");
01427     wxCommandEvent cmdEvt(wxEVT_COMMAND_BUTTON_CLICKED,XRCID("pano_button_stitch"));
01428     pano_panel->GetEventHandler()->AddPendingEvent(cmdEvt);
01429 }
01430 
01431 void MainFrame::OnUserDefinedStitch(wxCommandEvent & e)
01432 {
01433     pano_panel->DoUserDefinedStitch();
01434 }
01435 
01436 void MainFrame::OnMergeProject(wxCommandEvent & e)
01437 {
01438     // get the global config object
01439     wxConfigBase* config = wxConfigBase::Get();
01440 
01441     wxString defaultdir = config->Read(wxT("/actualPath"),wxT(""));
01442     wxFileDialog dlg(wxGetActiveWindow(),
01443                      _("Open project file"),
01444                      defaultdir, wxT(""),
01445                      _("Project files (*.pto)|*.pto|All files (*)|*"),
01446                      wxFD_OPEN, wxDefaultPosition);
01447     dlg.SetDirectory(defaultdir);
01448     if (dlg.ShowModal() == wxID_OK)
01449     {
01450         wxString filename = dlg.GetPath();
01451         wxFileName fname(filename);
01452         wxString path = fname.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
01453         if (fname.IsOk() && fname.FileExists())
01454         {
01455             wxBusyCursor wait;
01456             HuginBase::PanoramaMemento newPano;
01457             std::ifstream in((const char *)fname.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
01458             int ptoversion=0;
01459             if (newPano.loadPTScript(in, ptoversion, (const char *)path.mb_str(HUGIN_CONV_FILENAME)))
01460             {
01461                 HuginBase::Panorama new_pano;
01462                 new_pano.setMemento(newPano);
01463                 PanoCommand::GlobalCmdHist::getInstance().addCommand(
01464                     new PanoCommand::MergePanoCmd(pano, new_pano)
01465                 );
01466                 m_mruFiles.AddFileToHistory(fname.GetFullPath());
01467                 // force update of preview window
01468                 if ( !(preview_frame->IsIconized() ||(! preview_frame->IsShown()) ) )
01469                 {
01470                     wxCommandEvent dummy;
01471                     preview_frame->OnUpdate(dummy);
01472                 };
01473             }
01474             else
01475             {
01476                 wxMessageBox(wxString::Format(_("Could not read project file %s."),fname.GetFullPath().c_str()),_("Error"),wxOK|wxICON_ERROR);
01477             };
01478         };
01479     }
01480 }
01481 
01482 void MainFrame::OnReadPapywizard(wxCommandEvent & e)
01483 {
01484     wxString currentDir = wxConfigBase::Get()->Read(wxT("/actualPath"), wxT(""));
01485     wxFileDialog dlg(wxGetActiveWindow(), _("Open Papywizard xml file"),
01486         currentDir, wxT(""), _("Papywizard xml files (*.xml)|*.xml|All files (*)|*"),
01487         wxFD_OPEN, wxDefaultPosition);
01488     dlg.SetDirectory(currentDir);
01489     if (dlg.ShowModal() == wxID_OK)
01490     {
01491         wxConfigBase::Get()->Write(wxT("/actualPath"), dlg.GetDirectory());
01492         Papywizard::ImportPapywizardFile(dlg.GetPath(), pano);
01493     };
01494 };
01495 
01496 void MainFrame::OnApplyTemplate(wxCommandEvent & e)
01497 {
01498     // get the global config object
01499     wxConfigBase* config = wxConfigBase::Get();
01500 
01501     wxFileDialog dlg(wxGetActiveWindow(),
01502                      _("Choose template project"),
01503                      config->Read(wxT("/templatePath"),wxT("")), wxT(""),
01504                      _("Project files (*.pto)|*.pto|All files (*)|*"),
01505                      wxFD_OPEN, wxDefaultPosition);
01506     dlg.SetDirectory(wxConfigBase::Get()->Read(wxT("/templatePath"),wxT("")));
01507     if (dlg.ShowModal() == wxID_OK) {
01508         wxString filename = dlg.GetPath();
01509         wxConfig::Get()->Write(wxT("/templatePath"), dlg.GetDirectory());  // remember for later
01510 
01511         std::ifstream file((const char *)filename.mb_str(HUGIN_CONV_FILENAME));
01512 
01513         PanoCommand::GlobalCmdHist::getInstance().addCommand(
01514             new PanoCommand::wxApplyTemplateCmd(pano, file));
01515 
01516     }
01517 }
01518 
01519 void MainFrame::OnOpenPTBatcher(wxCommandEvent & e)
01520 {
01521 #if defined __WXMAC__ && defined MAC_SELF_CONTAINED_BUNDLE
01522         // Original patch for OSX by Charlie Reiman dd. 18 June 2011
01523         // Slightly modified by HvdW. Errors in here are mine, not Charlie's. 
01524         FSRef appRef;
01525         FSRef actuallyLaunched;
01526         OSStatus err;
01527         FSRef documentArray[1]; // Don't really need an array if we only have 1 item
01528         LSLaunchFSRefSpec launchSpec;
01529         Boolean  isDir;
01530         
01531         err = LSFindApplicationForInfo(kLSUnknownCreator,
01532                                                                    CFSTR("net.sourceforge.hugin.PTBatcherGUI"),
01533                                                                    NULL,
01534                                                                    &appRef,
01535                                                                    NULL);
01536         if (err != noErr) {
01537                 // error, can't find PTBatcherGUI
01538                 wxMessageBox(wxString::Format(_("External program %s not found in the bundle, reverting to system path"), wxT("open")), _("Error"));
01539                 // Possibly a silly attempt otherwise the previous would have worked as well, but just try it.
01540                 wxExecute(_T("open -b net.sourceforge.hugin.PTBatcherGUI"));
01541         }
01542         else {
01543                 wxExecute(_T("open -b net.sourceforge.hugin.PTBatcherGUI"));
01544         }       
01545 #else
01546     const wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
01547         wxExecute(exePath.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR) + _T("PTBatcherGUI"));
01548 #endif
01549 }
01550 
01551 void MainFrame::OnFineTuneAll(wxCommandEvent & e)
01552 {
01553     DEBUG_TRACE("");
01554     // fine-tune all points
01555 
01556     HuginBase::CPVector cps = pano.getCtrlPoints();
01557 
01558     // create a map of all control points.
01559     std::set<unsigned int> unoptimized;
01560     for (unsigned int i=0; i < cps.size(); i++) {
01561         // create all control points.
01562         unoptimized.insert(i);
01563     }
01564 
01565     unsigned int nGood=0;
01566     unsigned int nBad=0;
01567 
01568     wxConfigBase *cfg = wxConfigBase::Get();
01569     double corrThresh=HUGIN_FT_CORR_THRESHOLD;
01570     cfg->Read(wxT("/Finetune/CorrThreshold"), &corrThresh, HUGIN_FT_CORR_THRESHOLD);
01571     double curvThresh = HUGIN_FT_CURV_THRESHOLD;
01572     cfg->Read(wxT("/Finetune/CurvThreshold"),&curvThresh, HUGIN_FT_CURV_THRESHOLD);
01573     // load parameters
01574     const long templWidth = cfg->Read(wxT("/Finetune/TemplateSize"), HUGIN_FT_TEMPLATE_SIZE);
01575     const long sWidth = templWidth + cfg->Read(wxT("/Finetune/LocalSearchWidth"), HUGIN_FT_LOCAL_SEARCH_WIDTH);
01576 
01577     {
01578         ProgressReporterDialog progress(unoptimized.size(), _("Fine-tuning all points"), _("Fine-tuning"), wxGetActiveWindow());
01579 
01580     ImageCache & imgCache = ImageCache::getInstance();
01581 
01582     // do not process the control points in random order,
01583     // but walk from image to image, to reduce image reloading
01584     // in low mem situations.
01585     for (unsigned int imgNr = 0 ; imgNr < pano.getNrOfImages(); imgNr++) {
01586         std::set<unsigned int>::iterator it=unoptimized.begin();
01587 
01588         imgCache.softFlush();
01589 
01590         while (it != unoptimized.end()) {
01591             if (cps[*it].image1Nr == imgNr || cps[*it].image2Nr == imgNr) {
01592                 if (!progress.updateDisplayValue())
01593                 {
01594                     return;
01595                 };
01596                 if (cps[*it].mode == HuginBase::ControlPoint::X_Y) {
01597                     // finetune only normal points
01598                     DEBUG_DEBUG("fine tuning point: " << *it);
01599                     wxImage wxSearchImg;
01600                     ImageCache::ImageCacheRGB8Ptr searchImg = imgCache.getImage(
01601                         pano.getImage(cps[*it].image2Nr).getFilename())->get8BitImage();
01602 
01603                     ImageCache::ImageCacheRGB8Ptr templImg = imgCache.getImage(
01604                         pano.getImage(cps[*it].image1Nr).getFilename())->get8BitImage();
01605 
01606                     vigra_ext::CorrelationResult res;
01607                     vigra::Diff2D roundP1(hugin_utils::roundi(cps[*it].x1), hugin_utils::roundi(cps[*it].y1));
01608                     vigra::Diff2D roundP2(hugin_utils::roundi(cps[*it].x2), hugin_utils::roundi(cps[*it].y2));
01609 
01610                     res = PointFineTuneProjectionAware(pano.getImage(cps[*it].image1Nr), *templImg, roundP1, templWidth,
01611                         pano.getImage(cps[*it].image2Nr), *searchImg, roundP2, sWidth);
01612 
01613                     // invert curvature. we always assume its a maxima, the curvature there is negative
01614                     // however, we allow the user to specify a positive threshold, so we need to
01615                     // invert it
01616                     res.curv.x = - res.curv.x;
01617                     res.curv.y = - res.curv.y;
01618 
01619                     if (res.maxi < corrThresh || res.curv.x < curvThresh || res.curv.y < curvThresh ||
01620                         res.maxpos.x < 0 || res.maxpos.y < 0 || res.corrPos.x < 0 || res.corrPos.y < 0)
01621                     {
01622                         // Bad correlation result.
01623                         nBad++;
01624                         if (res.maxi >= corrThresh) {
01625                             cps[*it].error = 0;
01626                         }
01627                         cps[*it].error = res.maxi;
01628                         DEBUG_DEBUG("low correlation: " << res.maxi << " curv: " << res.curv);
01629                     } else {
01630                         nGood++;
01631                         // only update if a good correlation was found
01632                         cps[*it].x1 = res.corrPos.x;
01633                         cps[*it].y1 = res.corrPos.y;
01634                         cps[*it].x2 = res.maxpos.x;
01635                         cps[*it].y2 = res.maxpos.y;
01636                         cps[*it].error = res.maxi;
01637                     }
01638                 }
01639                 unsigned int rm = *it;
01640                 ++it;
01641                 unoptimized.erase(rm);
01642             } else {
01643                 ++it;
01644             }
01645         }
01646     }
01647     }
01648     wxString result;
01649     result.Printf(_("%d points fine-tuned, %d points not updated due to low correlation\n\nHint: The errors of the fine-tuned points have been set to the correlation coefficient\nProblematic points can be spotted (just after fine-tune, before optimizing)\nby an error <= %.3f.\nThe error of points without a well defined peak (typically in regions with uniform color)\nwill be set to 0\n\nUse the Control Point list (F3) to see all points of the current project\n"),
01650                   nGood, nBad, corrThresh);
01651     wxMessageBox(result, _("Fine-tune result"), wxOK);
01652     // set newly optimized points
01653     PanoCommand::GlobalCmdHist::getInstance().addCommand(
01654         new PanoCommand::UpdateCPsCmd(pano, cps, false)
01655         );
01656 }
01657 
01658 void MainFrame::OnRemoveCPinMasks(wxCommandEvent & e)
01659 {
01660     if(pano.getCtrlPoints().size()<2)
01661         return;
01662     HuginBase::UIntSet cps=getCPinMasks(pano);
01663     if(cps.size()>0)
01664     {
01665         PanoCommand::GlobalCmdHist::getInstance().addCommand(
01666                     new PanoCommand::RemoveCtrlPointsCmd(pano,cps)
01667                     );
01668         wxMessageBox(wxString::Format(_("Removed %lu control points"), static_cast<unsigned long>(cps.size())),
01669                    _("Removing control points in masks"),wxOK|wxICON_INFORMATION);
01670     };
01671 }
01672 
01673 #ifdef HUGIN_HSI
01674 void MainFrame::OnPythonScript(wxCommandEvent & e)
01675 {
01676     wxString fname;
01677     wxFileDialog dlg(wxGetActiveWindow(),
01678             _("Select python script"),
01679             wxConfigBase::Get()->Read(wxT("/lensPath"),wxT("")), wxT(""),
01680             _("Python script (*.py)|*.py|All files (*.*)|*.*"),
01681             wxFD_OPEN, wxDefaultPosition);
01682     dlg.SetDirectory(wxConfigBase::Get()->Read(wxT("/pythonScriptPath"),wxT("")));
01683 
01684     if (dlg.ShowModal() == wxID_OK)
01685     {
01686         wxString filename = dlg.GetPath();
01687         wxConfig::Get()->Write(wxT("/pythonScriptPath"), dlg.GetDirectory());
01688         std::string scriptfile((const char *)filename.mb_str(HUGIN_CONV_FILENAME));
01689         PanoCommand::GlobalCmdHist::getInstance().addCommand(
01690             new PanoCommand::PythonScriptPanoCmd(pano,scriptfile)
01691             );
01692     }
01693 }
01694 
01695 void MainFrame::OnPlugin(wxCommandEvent & e)
01696 {
01697     wxFileName file=m_plugins[e.GetId()];
01698     if(file.FileExists())
01699     {
01700         std::string scriptfile((const char *)file.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
01701         PanoCommand::GlobalCmdHist::getInstance().addCommand(
01702                                  new PanoCommand::PythonScriptPanoCmd(pano,scriptfile)
01703                                  );
01704     }
01705     else
01706     {
01707         wxMessageBox(wxString::Format(wxT("Python-Script %s not found.\nStopping processing."),file.GetFullPath().c_str()),_("Warning"),wxOK|wxICON_INFORMATION);
01708     };
01709 }
01710 
01711 #endif
01712 
01713 void MainFrame::OnUndo(wxCommandEvent & e)
01714 {
01715     DEBUG_TRACE("OnUndo");
01716     if (PanoCommand::GlobalCmdHist::getInstance().canUndo())
01717     {
01718         PanoCommand::GlobalCmdHist::getInstance().undo();
01719     }
01720     else
01721     {
01722         wxBell();
01723     };
01724 }
01725 
01726 void MainFrame::OnRedo(wxCommandEvent & e)
01727 {
01728     DEBUG_TRACE("OnRedo");
01729     if (PanoCommand::GlobalCmdHist::getInstance().canRedo())
01730     {
01731         PanoCommand::GlobalCmdHist::getInstance().redo();
01732     };
01733 }
01734 
01735 void MainFrame::ShowCtrlPoint(unsigned int cpNr)
01736 {
01737     DEBUG_DEBUG("Showing control point " << cpNr);
01738     m_notebook->SetSelection(2);
01739     cpe->ShowControlPoint(cpNr);
01740 }
01741 
01742 void MainFrame::ShowCtrlPointEditor(unsigned int img1, unsigned int img2)
01743 {
01744     if(!IsShown())
01745     {
01746         Show();
01747         Raise();
01748     };
01749     m_notebook->SetSelection(2);
01750     cpe->setLeftImage(img1);
01751     cpe->setRightImage(img2);
01752 }
01753 
01754 void MainFrame::ShowMaskEditor(size_t imgNr)
01755 {
01756     if(!IsShown())
01757     {
01758         Show();
01759         Raise();
01760     };
01761     m_notebook->SetSelection(1);
01762     mask_panel->setImage(imgNr, true);
01763 };
01764 
01765 void MainFrame::ShowStitcherTab()
01766 {
01768     if(m_show_opt_panel && m_show_opt_photo_panel)
01769     {
01770         m_notebook->SetSelection(5);
01771     }
01772     else
01773     {
01774         if(m_show_opt_panel || m_show_opt_photo_panel)
01775         {
01776             m_notebook->SetSelection(4);
01777         }
01778         else
01779         {
01780             m_notebook->SetSelection(3);
01781         };
01782     };
01783 }
01784 
01786 void MainFrame::updateProgressDisplay()
01787 {
01788     wxString msg;
01789     if (!m_message.empty())
01790     {
01791         msg = wxGetTranslation(wxString(m_message.c_str(), wxConvLocal));
01792         if (!m_filename.empty())
01793         {
01794             msg.Append(wxT(" "));
01795             msg.Append(wxString(ProgressDisplay::m_filename.c_str(), HUGIN_CONV_FILENAME));
01796         };
01797     };
01798     GetStatusBar()->SetStatusText(msg, 0);
01799 
01800 #ifdef __WXMSW__
01801     UpdateWindow(NULL);
01802 #endif
01803 }
01804 
01805 void MainFrame::enableTools(bool option)
01806 {
01807     wxToolBar* theToolBar = GetToolBar();
01808     theToolBar->EnableTool(XRCID("action_optimize"), option);
01809     theToolBar->EnableTool(XRCID("ID_SHOW_PREVIEW_FRAME"), option);
01810     //theToolBar->EnableTool(XRCID("ID_SHOW_GL_PREVIEW_FRAME"), option);
01811     wxMenuBar* theMenuBar = GetMenuBar();
01812     theMenuBar->Enable(XRCID("action_optimize"), option);
01813     theMenuBar->Enable(XRCID("action_finetune_all_cp"), option);
01814     theMenuBar->Enable(XRCID("action_remove_cp_in_masks"), option);
01815     theMenuBar->Enable(XRCID("ID_SHOW_PREVIEW_FRAME"), option);
01816     theMenuBar->Enable(XRCID("action_stitch"), option);
01817     theMenuBar->Enable(XRCID("action_stitch_userdefined"), option);
01818     m_menu_file_advanced->Enable(XRCID("action_import_papywizard"), option);
01819     //theMenuBar->Enable(XRCID("ID_SHOW_GL_PREVIEW_FRAME"), option);
01820 }
01821 
01822 
01823 void MainFrame::OnSize(wxSizeEvent &e)
01824 {
01825 #ifdef DEBUG
01826     wxSize sz = this->GetSize();
01827     wxSize csz = this->GetClientSize();
01828     wxSize vsz = this->GetVirtualSize();
01829     DEBUG_TRACE(" size:" << sz.x << "," << sz.y <<
01830                 " client: "<< csz.x << "," << csz.y <<
01831                 " virtual: "<< vsz.x << "," << vsz.y);
01832 #endif
01833 
01834     Layout();
01835     e.Skip();
01836 }
01837 
01838 CPDetectorSetting& MainFrame::GetDefaultSetting()
01839 {
01840     return images_panel->GetDefaultSetting();
01841 };
01842 
01843 void MainFrame::RunCPGenerator(CPDetectorSetting &setting, const HuginBase::UIntSet& img)
01844 {
01845     images_panel->RunCPGenerator(setting, img);
01846 };
01847 
01848 void MainFrame::RunCPGenerator(const HuginBase::UIntSet& img)
01849 {
01850     images_panel->RunCPGenerator(img);
01851 };
01852 
01853 const wxString MainFrame::GetSelectedCPGenerator()
01854 {
01855     return images_panel->GetSelectedCPGenerator();
01856 };
01857 
01858 const wxString & MainFrame::GetXRCPath()
01859 {
01860      return huginApp::Get()->GetXRCPath();
01861 };
01862 
01863 const wxString & MainFrame::GetDataPath()
01864 {
01865     return wxGetApp().GetDataPath();
01866 };
01867 
01869 MainFrame * MainFrame::Get()
01870 {
01871     if (m_this) {
01872         return m_this;
01873     } else {
01874         DEBUG_FATAL("MainFrame not yet created");
01875         DEBUG_ASSERT(m_this);
01876         return 0;
01877     }
01878 }
01879 
01880 wxString MainFrame::getProjectName()
01881 {
01882     return m_filename;
01883 }
01884 
01885 void MainFrame::OnMRUFiles(wxCommandEvent &e)
01886 {
01887     size_t index = e.GetId() - wxID_FILE1;
01888     wxString f(m_mruFiles.GetHistoryFile(index));
01889     if (!f.empty())
01890     {
01891         wxFileName fn(f);
01892         if(fn.FileExists())
01893             LoadProjectFile(f);
01894         else
01895         {
01896             m_mruFiles.RemoveFileFromHistory(index);
01897             wxMessageBox(wxString::Format(_("File \"%s\" not found.\nMaybe file was renamed, moved or deleted."),f.c_str()),
01898                 _("Error!"),wxOK | wxICON_INFORMATION );
01899         };
01900     };
01901 }
01902 
01903 void MainFrame::OnFullScreen(wxCommandEvent & e)
01904 {
01905     ShowFullScreen(!IsFullScreen(), wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION);
01906 #ifdef __WXGTK__
01907     //workaround a wxGTK bug that also the toolbar is hidden, but not requested to hide
01908     GetToolBar()->Show(true);
01909 #endif
01910 };
01911 
01912 struct celeste::svm_model* MainFrame::GetSVMModel()
01913 {
01914     if(svmModel==NULL)
01915     {
01916         // determine file name of SVM model file
01917         // get XRC path from application
01918         wxString wxstrModelFileName = huginApp::Get()->GetDataPath() + wxT(HUGIN_CELESTE_MODEL);
01919         // convert wxString to string
01920         std::string strModelFileName(wxstrModelFileName.mb_str(HUGIN_CONV_FILENAME));
01921 
01922         // SVM model file
01923         if (! wxFile::Exists(wxstrModelFileName) ) {
01924             wxMessageBox(wxString::Format(_("Celeste model expected in %s not found, Hugin needs to be properly installed."),wxstrModelFileName.c_str()), _("Fatal Error"));
01925             return NULL;
01926         }
01927         if(!celeste::loadSVMmodel(svmModel,strModelFileName))
01928         {
01929             wxMessageBox(wxString::Format(_("Could not load Celeste model file %s"),wxstrModelFileName.c_str()),_("Error"));
01930             svmModel=NULL;
01931         };
01932     }
01933     return svmModel;
01934 };
01935 
01936 GLPreviewFrame * MainFrame::getGLPreview()
01937 {
01938     return gl_preview_frame;
01939 }
01940 
01941 void MainFrame::SetGuiLevel(GuiLevel newLevel)
01942 {
01943     if(gl_preview_frame==NULL && newLevel==GUI_SIMPLE)
01944     {
01945         SetGuiLevel(GUI_ADVANCED);
01946         return;
01947     };
01948     if(m_guiLevel==GUI_EXPERT && newLevel!=GUI_EXPERT && pano.getOptimizerSwitch()==0)
01949     {
01950         bool needsUpdateOptimizerVar=false;
01951         HuginBase::OptimizeVector optVec = pano.getOptimizeVector();
01952         for(size_t i=0; i<optVec.size(); i++)
01953         {
01954             bool hasTrX=optVec[i].erase("TrX")>0;
01955             bool hasTrY=optVec[i].erase("TrY")>0;
01956             bool hasTrZ=optVec[i].erase("TrZ")>0;
01957             bool hasTpy=optVec[i].erase("Tpy")>0;
01958             bool hasTpp=optVec[i].erase("Tpp")>0;
01959             bool hasg=optVec[i].erase("g")>0;
01960             bool hast=optVec[i].erase("t")>0;
01961             needsUpdateOptimizerVar=needsUpdateOptimizerVar || hasTrX || hasTrY || hasTrZ || hasTpy || hasTpp || hasg || hast;
01962         };
01963         if(needsUpdateOptimizerVar)
01964         {
01965             PanoCommand::GlobalCmdHist::getInstance().addCommand(
01966                 new PanoCommand::UpdateOptimizeVectorCmd(pano, optVec)
01967             );
01968         };
01969     };
01970     if(newLevel==GUI_SIMPLE && pano.getPhotometricOptimizerSwitch()==0)
01971     {
01972         bool needsUpdateOptimizerVar=false;
01973         HuginBase::OptimizeVector optVec = pano.getOptimizeVector();
01974         for(size_t i=0; i<optVec.size(); i++)
01975         {
01976             bool hasVx=optVec[i].erase("Vx")>0;
01977             bool hasVy=optVec[i].erase("Vy")>0;
01978             needsUpdateOptimizerVar=needsUpdateOptimizerVar || hasVx || hasVy;
01979         };
01980         if(needsUpdateOptimizerVar)
01981         {
01982             PanoCommand::GlobalCmdHist::getInstance().addCommand(
01983                 new PanoCommand::UpdateOptimizeVectorCmd(pano, optVec)
01984             );
01985         };
01986     };
01987     m_guiLevel=newLevel;
01988     images_panel->SetGuiLevel(m_guiLevel);
01989     opt_panel->SetGuiLevel(m_guiLevel);
01990     opt_photo_panel->SetGuiLevel(m_guiLevel);
01991     pano_panel->SetGuiLevel(m_guiLevel);
01992     if(gl_preview_frame)
01993     {
01994         gl_preview_frame->SetGuiLevel(m_guiLevel);
01995     };
01996     switch(m_guiLevel)
01997     {
01998         case GUI_SIMPLE:
01999             GetMenuBar()->FindItem(XRCID("action_gui_simple"))->Check();
02000             break;
02001         case GUI_ADVANCED:
02002             GetMenuBar()->FindItem(XRCID("action_gui_advanced"))->Check();
02003             break;
02004         case GUI_EXPERT:
02005             GetMenuBar()->FindItem(XRCID("action_gui_expert"))->Check();
02006             break;
02007     };
02008     if(m_guiLevel==GUI_SIMPLE)
02009     {
02010         if(!gl_preview_frame->IsShown())
02011         {
02012             wxCommandEvent dummy;
02013             OnToggleGLPreviewFrame(dummy);
02014         };
02015         wxGetApp().SetTopWindow(gl_preview_frame);
02016         GetMenuBar()->Remove(0);
02017         GetMenuBar()->Insert(0, m_menu_file_simple, _("&File"));
02018         if(m_filename.IsEmpty())
02019         {
02020             gl_preview_frame->SetTitle(_("Hugin - Panorama Stitcher"));
02021             SetTitle(_("Panorama editor"));
02022         }
02023         else
02024         {
02025             wxFileName scriptName = m_filename;
02026             gl_preview_frame->SetTitle(scriptName.GetName() + wxT(".") + scriptName.GetExt() + wxT(" - ") + _("Hugin - Panorama Stitcher"));
02027             SetTitle(scriptName.GetName() + wxT(".") + scriptName.GetExt() + wxT(" - ") + _("Panorama editor"));
02028         };
02029         Hide();
02030     }
02031     else
02032     {
02033         wxGetApp().SetTopWindow(this);
02034         GetMenuBar()->Remove(0);
02035         GetMenuBar()->Insert(0, m_menu_file_advanced, _("&File"));
02036         if(m_filename.IsEmpty())
02037         {
02038             SetTitle(_("Hugin - Panorama Stitcher"));
02039         }
02040         else
02041         {
02042             wxFileName scriptName = m_filename;
02043             SetTitle(scriptName.GetName() + wxT(".") + scriptName.GetExt() + wxT(" - ") + _("Hugin - Panorama Stitcher"));
02044         };
02045         if(!IsShown())
02046         {
02047             Show();
02048         };
02049     };
02050 };
02051 
02052 void MainFrame::OnSetGuiSimple(wxCommandEvent & e)
02053 {
02054     GuiLevel reqGuiLevel=GetMinimumGuiLevel(pano);
02055     if(reqGuiLevel<=GUI_SIMPLE)
02056     {
02057         SetGuiLevel(GUI_SIMPLE);
02058     }
02059     else
02060     {
02061         if(reqGuiLevel==GUI_ADVANCED)
02062         {
02063             wxMessageBox(_("Can't switch to simple interface. The project is using stacks and/or vignetting center shift.\nThese features are not supported in simple interface."),
02064 #ifdef __WXMSW__
02065                          wxT("Hugin"),
02066 #else
02067                          wxT(""),
02068 #endif
02069                          wxOK | wxICON_INFORMATION);
02070         }
02071         else
02072         {
02073             wxMessageBox(_("Can't switch to simple interface. The project is using translation or shear parameters.\nThese parameters are not supported in simple interface."),
02074 #ifdef __WXMSW__
02075                          wxT("Hugin"),
02076 #else
02077                          wxT(""),
02078 #endif
02079                          wxOK | wxICON_INFORMATION);
02080         }
02081         SetGuiLevel(m_guiLevel);
02082     };
02083 };
02084 
02085 void MainFrame::OnSetGuiAdvanced(wxCommandEvent & e)
02086 {
02087     GuiLevel reqGuiLevel=GetMinimumGuiLevel(pano);
02088     if(reqGuiLevel<=GUI_ADVANCED)
02089     {
02090         SetGuiLevel(GUI_ADVANCED);
02091     }
02092     else
02093     {
02094         wxMessageBox(_("Can't switch to advanced interface. The project is using translation or shear parameters.\nThese parameters are not supported in advanced interface."),
02095 #ifdef __WXMSW__
02096                      wxT("Hugin"),
02097 #else
02098                      wxT(""),
02099 #endif
02100                      wxOK | wxICON_INFORMATION);
02101         SetGuiLevel(GUI_EXPERT);
02102     };
02103 };
02104 
02105 void MainFrame::OnSetGuiExpert(wxCommandEvent & e)
02106 {
02107     SetGuiLevel(GUI_EXPERT);
02108 };
02109 
02110 void MainFrame::DisableOpenGLTools()
02111 {
02112     GetMenuBar()->Enable(XRCID("ID_SHOW_GL_PREVIEW_FRAME"), false);
02113     GetMenuBar()->Enable(XRCID("action_gui_simple"), false);
02114     GetToolBar()->EnableTool(XRCID("ID_SHOW_GL_PREVIEW_FRAME"), false); 
02115 };
02116 
02117 void MainFrame::RunAssistant(wxWindow* mainWin)
02118 {
02119     if (pano.getNrOfImages() < 2)
02120     {
02121         wxMessageBox(_("At least two images are required.\nPlease add more images."),_("Error"), wxOK, mainWin);
02122         return;
02123     }
02124 
02125     //save project into temp directory
02126     wxString tempDir= wxConfig::Get()->Read(wxT("tempDir"),wxT(""));
02127     if(!tempDir.IsEmpty())
02128     {
02129         if(tempDir.Last()!=wxFileName::GetPathSeparator())
02130         {
02131             tempDir.Append(wxFileName::GetPathSeparator());
02132         }
02133     };
02134     wxFileName scriptFileName(wxFileName::CreateTempFileName(tempDir+wxT("ha")));
02135     std::ofstream script(scriptFileName.GetFullPath().mb_str(HUGIN_CONV_FILENAME));
02136     script.exceptions ( std::ofstream::eofbit | std::ofstream::failbit | std::ofstream::badbit );
02137     HuginBase::UIntSet all;
02138     fill_set(all, 0, pano.getNrOfImages()-1);
02139     pano.printPanoramaScript(script, pano.getOptimizeVector(), pano.getOptions(), all, false);
02140     script.close();
02141 
02142     // get assistant queue
02143     const wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
02144     HuginQueue::CommandQueue* commands = HuginQueue::GetAssistantCommandQueue(pano, exePath.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR), scriptFileName.GetFullPath());
02145     //execute queue
02146     int ret = MyExecuteCommandQueue(commands, mainWin, _("Running assistant"));
02147 
02148     //read back panofile
02149     PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::wxLoadPTProjectCmd(pano,
02150         (const char *)scriptFileName.GetFullPath().mb_str(HUGIN_CONV_FILENAME), 
02151         (const char *)scriptFileName.GetPath(wxPATH_NATIVE | wxPATH_GET_SEPARATOR).mb_str(HUGIN_CONV_FILENAME), 
02152         ret==0, false));
02153 
02154     //delete temporary files
02155     wxRemoveFile(scriptFileName.GetFullPath());
02156     //if return value is non-zero, an error occurred in the assistant
02157     if(ret!=0)
02158     {
02159         //check for unconnected images
02160         HuginGraph::ImageGraph graph(pano);
02161         const HuginGraph::ImageGraph::Components comps = graph.GetComponents();
02162         if(comps.size() > 1)
02163         {
02164             // switch to images panel.
02165             unsigned i1 = *(comps[0].rbegin());
02166             unsigned i2 = *(comps[1].begin());
02167             ShowCtrlPointEditor( i1, i2);
02168             // display message box with 
02169             wxMessageBox(wxString::Format(_("Warning %d unconnected image groups found:"), comps.size()) + Components2Str(comps) + wxT("\n")
02170                 + _("Please create control points between unconnected images using the Control Points tab in the panorama editor.\n\nAfter adding the points, press the \"Align\" button again"),_("Error"), wxOK , mainWin);
02171             return;
02172         };
02173         wxMessageBox(_("The assistant did not complete successfully. Please check the resulting project file."),
02174                      _("Warning"),wxOK | wxICON_INFORMATION, mainWin); 
02175     };
02176 };
02177 
02178 void MainFrame::OnRunAssistant(wxCommandEvent & e)
02179 {
02180     RunAssistant(this);
02181 };
02182 
02183 void MainFrame::OnSendToAssistantQueue(wxCommandEvent &e)
02184 {
02185     wxCommandEvent dummy;
02186     OnSaveProject(dummy);
02187     wxString projectFile = getProjectName();
02188     if(wxFileName::FileExists(projectFile))
02189     {
02190 #if defined __WXMAC__ && defined MAC_SELF_CONTAINED_BUNDLE
02191         // Original patch for OSX by Charlie Reiman dd. 18 June 2011
02192         // Slightly modified by HvdW. Errors in here are mine, not Charlie's. 
02193         FSRef appRef;
02194         FSRef actuallyLaunched;
02195         OSStatus err;
02196         FSRef documentArray[1]; // Don't really need an array if we only have 1 item
02197         LSLaunchFSRefSpec launchSpec;
02198         Boolean  isDir;
02199 
02200         err = LSFindApplicationForInfo(kLSUnknownCreator,
02201                                        CFSTR("net.sourceforge.hugin.PTBatcherGUI"),
02202                                        NULL,
02203                                        &appRef,
02204                                        NULL);
02205         if (err != noErr)
02206         {
02207             // error, can't find PTBatcherGUI
02208             wxMessageBox(wxString::Format(_("External program %s not found in the bundle, reverting to system path"), wxT("open")), _("Error"));
02209             // Possibly a silly attempt otherwise the previous would have worked as well, but just try it.
02210             wxExecute(_T("open -b net.sourceforge.hugin.PTBatcherGUI ")+hugin_utils::wxQuoteFilename(projectFile));
02211             return;
02212         }
02213 
02214         wxCharBuffer projectFilebuffer=projectFile.ToUTF8();
02215         // Point to document
02216         err = FSPathMakeRef((unsigned char*) projectFilebuffer.data(), &documentArray[0], &isDir);
02217         if (err != noErr || isDir)
02218         {
02219             // Something went wrong.
02220             wxMessageBox(wxString::Format(_("Project file not found"), wxT("open")), _("Error"));
02221             return;
02222         }
02223         launchSpec.appRef = &appRef;
02224         launchSpec.numDocs = sizeof(documentArray)/sizeof(documentArray[0]);
02225         launchSpec.itemRefs = documentArray;
02226         launchSpec.passThruParams = NULL;
02227         launchSpec.launchFlags = kLSLaunchDontAddToRecents + kLSLaunchDontSwitch;
02228         launchSpec.asyncRefCon = NULL;
02229 
02230         err = LSOpenFromRefSpec(&launchSpec, &actuallyLaunched);
02231         if (err != noErr && err != kLSLaunchInProgressErr)
02232         {  
02233             // Should be ok if it's in progress... I think. 
02234             // Launch failed.
02235             wxMessageBox(wxString::Format(_("Can't launch PTBatcherGui"), wxT("open")), _("Error"));
02236             return;
02237         }
02238 
02239         // Should verify that actuallyLaunched and appRef are the same.
02240         if (FSCompareFSRefs(&appRef, &actuallyLaunched) != noErr)
02241         {
02242             // error, lauched the wrong thing.
02243             wxMessageBox(wxString::Format(_("Launched incorrect programme"), wxT("open")), _("Error"));
02244             return;
02245         }
02246 #else
02247         const wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
02248         wxExecute(exePath.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR) + wxT("PTBatcherGUI -a ")+hugin_utils::wxQuoteFilename(projectFile));
02249 #endif
02250     }
02251 };
02252 
02253 wxString MainFrame::GetCurrentOptimizerString()
02254 {
02255     return images_panel->GetCurrentOptimizerString();
02256 };
02257 
02258 MainFrame * MainFrame::m_this = 0;

Generated on 5 May 2016 for Hugintrunk by  doxygen 1.4.7