1 //####COPYRIGHTBEGIN####
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
5 // Copyright (C) 2003 John Dallaway
7 // This program is part of the eCos host tools.
9 // This program is free software; you can redistribute it and/or modify it
10 // under the terms of the GNU General Public License as published by the Free
11 // Software Foundation; either version 2 of the License, or (at your option)
14 // This program is distributed in the hope that it will be useful, but WITHOUT
15 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 // You should have received a copy of the GNU General Public License along with
20 // this program; if not, write to the Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 // ----------------------------------------------------------------------------
25 //####COPYRIGHTEND####
28 //===========================================================================
29 //#####DESCRIPTIONBEGIN####
31 // Author(s): julians, jld
32 // Contact(s): julians, jld
36 // Description: Implementation file for the ConfigTool application class
43 //####DESCRIPTIONEND####
45 //===========================================================================
47 // ============================================================================
49 // ============================================================================
51 // ----------------------------------------------------------------------------
53 // ----------------------------------------------------------------------------
55 #pragma implementation "configtool.h"
58 // Includes other headers for precompiled compilation
65 #include "eCosSocket.h"
66 #include "eCosTestPlatform.h"
68 #include "wx/splash.h"
69 #include "wx/cshelp.h"
71 #include "wx/filesys.h"
72 #include "wx/fs_zip.h"
73 #include "wx/config.h"
74 #include "wx/cmdline.h"
75 #include "wx/process.h"
76 #include "wx/mimetype.h"
77 #include "wx/txtstrm.h"
78 #include "wx/wfstream.h"
79 #include "wx/fs_mem.h"
81 #include "configtool.h"
82 #include "configtoolview.h"
83 #include "configtree.h"
85 #include "outputwin.h"
86 #include "configtooldoc.h"
88 #include "shortdescrwin.h"
89 #include "conflictwin.h"
90 #include "propertywin.h"
93 #include "Subprocess.h"
95 // ----------------------------------------------------------------------------
97 // ----------------------------------------------------------------------------
98 // the application icon
99 #if defined(__WXGTK__) || defined(__WXMOTIF__)
100 #include "bitmaps/configtool.xpm"
103 // Create a new application object.
106 BEGIN_EVENT_TABLE(ecApp, wxApp)
107 // Don't handle automatically, or it will bypass more specific processing.
108 // EVT_MENU(ecID_WHATS_THIS, ecApp::OnWhatsThis)
111 bool ecApp::sm_arMounted[26]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
113 static const wxCmdLineEntryDesc sg_cmdLineDesc[] =
116 { wxCMD_LINE_SWITCH, "v", "verbose", "be verbose" },
117 { wxCMD_LINE_SWITCH, "q", "quiet", "be quiet" },
119 { wxCMD_LINE_OPTION, "o", "output", "output file" },
120 { wxCMD_LINE_OPTION, "i", "input", "input dir" },
121 { wxCMD_LINE_OPTION, "s", "size", "output block size", wxCMD_LINE_VAL_NUMBER },
122 { wxCMD_LINE_OPTION, "d", "date", "output file date", wxCMD_LINE_VAL_DATE },
124 { wxCMD_LINE_SWITCH, "h", "help", "displays help on the command line parameters" },
125 { wxCMD_LINE_SWITCH, "e", "edit-only", "edit save file only" },
126 { wxCMD_LINE_SWITCH, "v", "version", "print version" },
127 { wxCMD_LINE_SWITCH, "c", "compile-help", "compile online help only" },
129 { wxCMD_LINE_PARAM, NULL, NULL, "input file 1", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
130 { wxCMD_LINE_PARAM, NULL, NULL, "input file 2", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
140 m_whatsThisMenu = new wxMenu;
141 m_whatsThisMenu->Append(ecID_WHATS_THIS, _("&What's This?"));
142 m_helpFile = wxEmptyString;
143 m_splashScreen = NULL;
144 m_pipedProcess = NULL;
146 m_helpController = NULL;
147 m_fileSystem = new wxFileSystem;
148 #if wxUSE_STREAMS && wxUSE_ZIPSTREAM && wxUSE_ZLIB
149 m_zipHandler = new wxZipFSHandler;
155 delete m_whatsThisMenu;
159 // 'Main program' equivalent: the program execution "starts" here
162 wxLog::SetTimestamp(NULL);
164 wxHelpProvider::Set(new wxSimpleHelpProvider);
165 //wxHelpProvider::Set(new wxHelpControllerHelpProvider(& m_helpController));
167 wxImage::AddHandler(new wxPNGHandler);
168 wxImage::AddHandler(new wxGIFHandler);
170 // Required for advanced HTML help
171 #if wxUSE_STREAMS && wxUSE_ZIPSTREAM && wxUSE_ZLIB
172 wxFileSystem::AddHandler(m_zipHandler);
175 // Mandatory initialisation for Tcl 8.4
176 Tcl_FindExecutable(argv[0]);
178 wxString currentDir = wxGetCwd();
180 // Use argv to get current app directory
181 m_appDir = wxFindAppPath(argv[0], currentDir, wxT("CONFIGTOOLDIR"));
183 // If the development version, go up a directory.
185 if ((m_appDir.Right(5).CmpNoCase("DEBUG") == 0) ||
186 (m_appDir.Right(11).CmpNoCase("DEBUGSTABLE") == 0) ||
187 (m_appDir.Right(7).CmpNoCase("RELEASE") == 0) ||
188 (m_appDir.Right(13).CmpNoCase("RELEASESTABLE") == 0)
190 m_appDir = wxPathOnly(m_appDir);
193 // Install default platform definitions if no platforms defined
195 wxConfig config (wxGetApp().GetSettings().GetConfigAppName());
196 if (! config.Exists (wxT("Platforms")))
198 wxFileName platforms (m_appDir, wxT("platforms.reg"));
199 platforms.Normalize();
200 if (platforms.FileExists())
201 wxExecute (wxT("regedit /s \"") + platforms.GetFullPath() + wxT("\""), wxEXEC_SYNC);
205 wxFileName config (wxFileName::GetHomeDir(), wxEmptyString);
206 config.AppendDir(wxT(".eCosPlatforms"));
207 if (! config.DirExists())
209 wxFileName platforms (m_appDir, wxT("platforms.tar"));
210 platforms.Normalize();
211 if (platforms.FileExists())
212 wxExecute (wxT("tar -C ") + wxFileName::GetHomeDir() + wxT(" -xf ") + platforms.GetFullPath(), wxEXEC_SYNC);
217 CeCosTestPlatform::Load();
219 // Load resources from binary resources archive, or failing that, from
220 // Windows resources or plain files
223 wxGetEnv(wxT("PATH"), & m_strOriginalPath);
225 // Create a document manager
226 m_docManager = new wxDocManager;
228 // Create a template relating documents to their views
229 wxDocTemplate* templ = new wxDocTemplate(m_docManager, "Configtool", "*.ecc", "", "ecc", "Configtool Doc", "Configtool View",
230 CLASSINFO(ecConfigToolDoc), CLASSINFO(ecConfigToolView));
232 // If we've only got one window, we only get to edit
233 // one document at a time.
234 m_docManager->SetMaxDocsOpen(1);
236 // Initialize config settings
239 // Let wxWindows know what the app name is
240 SetAppName(m_settings.GetAppName());
242 InitializeWindowSettings(TRUE /* beforeWindowConstruction */) ;
244 // Load config settings
245 m_settings.LoadConfig();
247 // Set the default directory for opening/saving files
248 if (!m_settings.m_lastFilename.IsEmpty())
249 templ->SetDirectory(wxPathOnly(m_settings.m_lastFilename));
251 // Parse the command-line parameters and options
252 wxCmdLineParser parser(sg_cmdLineDesc, argc, argv);
256 res = parser.Parse();
258 if (res == -1 || res > 0 || parser.Found(wxT("h")))
261 wxLog::SetActiveTarget(new wxLogStderr);
266 if (parser.Found(wxT("v")))
269 wxLog::SetActiveTarget(new wxLogStderr);
272 msg.Printf(wxT("eCos Configuration Tool (c) Red Hat, 2001 Version %s, %s"), ecCONFIGURATION_TOOL_VERSION, __DATE__);
279 wxBitmap bitmap(wxBITMAP(splash));
282 if (wxFileExists("splash16.png"))
283 bitmap.LoadFile("splash16.png", wxBITMAP_TYPE_PNG);
287 // wxYieldIfNeeded();
289 // create the main application window
290 ecMainFrame *frame = new ecMainFrame(m_docManager, GetSettings().GetAppName(),
291 wxPoint(GetSettings().m_frameSize.x, GetSettings().m_frameSize.y),
292 wxSize(GetSettings().m_frameSize.width, GetSettings().m_frameSize.height));
297 SendIdleEvents(); // Otherwise UI updates aren't done, because it's busy loading the repository
299 ::UpdateWindow((HWND) frame->GetHWND());
302 InitializeWindowSettings(FALSE /* beforeWindowConstruction */) ;
304 if (m_splashScreenBitmap.Ok() && GetSettings().m_showSplashScreen)
306 m_splashScreen = new ecSplashScreen(m_splashScreenBitmap, wxSPLASH_CENTRE_ON_SCREEN|wxSPLASH_TIMEOUT,
307 5000, NULL, -1, wxDefaultPosition, wxDefaultSize, wxNO_BORDER|wxFRAME_FLOAT_ON_PARENT|wxSTAY_ON_TOP);
310 // if (m_splashScreen)
311 // m_splashScreen->Raise();
315 if (parser.Found(wxT("e")))
316 GetSettings().m_editSaveFileOnly = TRUE;
318 // If in --compile-help (-c) mode, then exit immediately after recompiling help file
319 bool compileHelpOnly = parser.Found(wxT("c"));
321 wxString filenameToOpen1, filenameToOpen2;
322 if (parser.GetParamCount() > 0)
324 wxString tmpSaveFile;
326 filenameToOpen1 = parser.GetParam(0);
328 if (parser.GetParamCount() > 1)
329 filenameToOpen2 = parser.GetParam(1);
331 bool gotRepository = FALSE;
332 bool gotSavefile = FALSE;
334 wxString repositoryDir, saveFile;
336 // Might be e.g. . or .. in path, or relative path
337 filenameToOpen1 = wxGetRealPath(currentDir, filenameToOpen1);
339 if (parser.GetParamCount() > 1)
340 filenameToOpen2 = wxGetRealPath(currentDir, filenameToOpen2);
342 wxString path1, name1, ext1;
343 wxSplitPath(filenameToOpen1, & path1, & name1, & ext1);
345 wxString path2, name2, ext2;
346 wxSplitPath(filenameToOpen2, & path2, & name2, & ext2);
348 // Look at the first file
349 if (ext1 == "ecc" || ext1 == "ECC")
351 if (wxFileExists(filenameToOpen1))
354 saveFile = filenameToOpen1;
359 msg.Printf("%s is not a valid file.", (const wxChar*) filenameToOpen1);
360 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
364 else if (wxDirExists(filenameToOpen1) && FindSaveFileInDir(filenameToOpen1, tmpSaveFile))
366 saveFile = tmpSaveFile;
369 else if ((name1 == wxT("ecos") && ext1 == wxT("db") && wxFileExists(filenameToOpen1)) || wxDirExists(filenameToOpen1))
371 // It's a repository (we hope).
372 if (name1 == wxT("ecos") && ext1 == wxT("db"))
375 filenameToOpen1 = wxPathOnly(filenameToOpen1);
376 filenameToOpen1 = wxPathOnly(filenameToOpen1);
380 // If it's the packages directory, we need to strip off
382 wxString eccPath(filenameToOpen1 + wxString(wxFILE_SEP_PATH) + wxT("ecc"));
384 // Don't strip off ecc if it's the CVS repository (with ecc below it)
385 if (name1 == wxT("packages") || (name1 == wxT("ecc") && !wxDirExists(eccPath)))
386 filenameToOpen1 = wxPathOnly(filenameToOpen1);
389 repositoryDir = filenameToOpen1;
390 gotRepository = TRUE;
395 msg.Printf("%s is neither a project file nor a valid repository.", (const wxChar*) filenameToOpen1);
396 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
400 // Look at the second file, if any
401 if (parser.GetParamCount() > 1)
403 if (ext2 == "ecc" || ext2 == "ECC")
405 if (wxFileExists(filenameToOpen2))
410 msg.Printf("%s is a second save file -- please supply only one.", (const wxChar*) filenameToOpen2);
411 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
416 saveFile = filenameToOpen2;
421 msg.Printf("%s is not a valid file.", (const wxChar*) filenameToOpen2);
422 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
426 else if (!gotSavefile && wxDirExists(filenameToOpen2) && FindSaveFileInDir(filenameToOpen2, tmpSaveFile))
428 saveFile = tmpSaveFile;
431 else if ((name2 == wxT("ecos") && ext2 == wxT("db") && wxFileExists(filenameToOpen2)) || wxDirExists(filenameToOpen2))
436 msg.Printf("%s is a second repository -- please supply only one.", (const wxChar*) filenameToOpen2);
437 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
441 // It's a repository (we hope).
442 if (name1 == wxT("ecos") && ext1 == wxT("db"))
445 filenameToOpen2 = wxPathOnly(filenameToOpen2);
446 filenameToOpen2 = wxPathOnly(filenameToOpen2);
450 // If it's the packages directory, we need to strip off
452 wxString eccPath(filenameToOpen2 + wxString(wxFILE_SEP_PATH) + wxT("ecc"));
454 // Don't strip off ecc if it's the CVS repository (with ecc below it)
455 if (name2 == wxT("packages") || (name2 == wxT("ecc") && !wxDirExists(eccPath)))
456 filenameToOpen2 = wxPathOnly(filenameToOpen2);
459 repositoryDir = filenameToOpen2;
460 gotRepository = TRUE;
465 msg.Printf("%s is neither a project file nor a valid repository.", (const wxChar*) filenameToOpen2);
466 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
471 // Now we have looked at the two files and decided what they are; let's
476 GetSettings().m_strRepository = repositoryDir;
481 // See if there's a save file in the current dir
482 if (FindSaveFileInDir(currentDir, saveFile))
488 // The repository will be loaded from m_strRepository, possibly set above.
489 m_docManager->CreateDocument(saveFile, wxDOC_SILENT);
494 m_docManager->CreateDocument(wxString(""), wxDOC_NEW);
502 msg.Printf(wxT("Please specify a repository when using the --compile-help option."));
503 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
506 ecConfigToolDoc* doc = wxGetApp().GetConfigToolDoc();
509 if (!doc->RebuildHelpIndex(TRUE))
512 msg.Printf(wxT("Sorry, there was a problem compiling the help index."));
513 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
520 msg.Printf(wxT("Sorry, there was no current document when compiling the help index."));
521 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
525 // Return FALSE in order to quit the application
531 if (GetSettings().m_strRepository.IsEmpty()) // first invocation by this user
533 // we have no clues as to the location of the repository so
534 // test for ../../packages relative to the configtool location
535 wxFileName repository = wxFileName (m_appDir, wxEmptyString);
536 repository.Normalize(); // remove trailing "./" if present
537 repository.RemoveDir (repository.GetDirCount()-1);
538 repository.RemoveDir (repository.GetDirCount()-1);
539 repository.AppendDir (wxT("packages"));
540 if (repository.DirExists()) // we've found a repository
542 repository.RemoveDir (repository.GetDirCount()-1);
543 GetSettings().m_strRepository = repository.GetFullPath();
546 m_docManager->CreateDocument(wxString(""), wxDOC_NEW);
552 // Load resources from disk
553 bool ecApp::LoadResources()
555 wxFileSystem::AddHandler(new wxMemoryFSHandler);
557 // LoadBitmapResource(m_splashScreenBitmap, wxT("splash16.png"), wxBITMAP_TYPE_PNG, FALSE);
559 // wxBitmap bitmap1, bitmap2, bitmap3;
560 // LoadBitmapResource(bitmap1, wxT("ecoslogo.png"), wxBITMAP_TYPE_PNG, TRUE);
561 // LoadBitmapResource(bitmap2, wxT("ecoslogosmall.png"), wxBITMAP_TYPE_PNG, TRUE);
562 // LoadBitmapResource(bitmap3, wxT("rhlogo.png"), wxBITMAP_TYPE_PNG, TRUE);
564 // wxString aboutText;
565 // LoadTextResource(aboutText, wxT("about.htm"), TRUE);
567 // VersionStampSplashScreen();
572 // Load resources from zip resource file or disk
573 bool ecApp::LoadBitmapResource(wxBitmap& bitmap, const wxString& filename, int bitmapType, bool addToMemoryFS)
575 wxString archive(GetFullAppPath(wxT("configtool.bin")));
577 #if wxUSE_STREAMS && wxUSE_ZIPSTREAM && wxUSE_ZLIB
578 wxFSFile* file = m_fileSystem->OpenFile(archive + wxString(wxT("#zip:")) + filename);
581 wxInputStream* stream = file->GetStream();
583 wxImage image(* stream, bitmapType);
584 bitmap = image.ConvertToBitmap();
592 bitmap.LoadFile(filename, wxBITMAP_TYPE_BMP_RESOURCE);
595 if (!bitmap.Ok() && wxFileExists(GetFullAppPath(filename)))
596 bitmap.LoadFile(GetFullAppPath(filename), bitmapType);
599 if (bitmap.Ok() && addToMemoryFS)
600 wxMemoryFSHandler::AddFile(filename, bitmap, bitmapType);
605 // Load resources from zip resource file or disk
606 bool ecApp::LoadTextResource(wxString& text, const wxString& filename, bool addToMemoryFS)
608 wxString archive(GetFullAppPath(wxT("configtool.bin")));
610 bool success = FALSE;
612 #if wxUSE_STREAMS && wxUSE_ZIPSTREAM && wxUSE_ZLIB
613 wxFSFile* file = m_fileSystem->OpenFile(archive + wxString(wxT("#zip:")) + filename);
616 wxInputStream* stream = file->GetStream();
618 char* buf = text.GetWriteBuf(stream->GetSize() + 1);
619 stream->Read((void*) buf, stream->GetSize());
620 buf[stream->GetSize()] = 0;
621 text.UngetWriteBuf();
629 if (!success && wxFileExists(GetFullAppPath(filename)))
631 wxFileInputStream str(GetFullAppPath(filename));
633 char* buf = text.GetWriteBuf(str.GetSize() + 1);
634 str.Read((void*) buf, str.GetSize());
635 buf[str.GetSize()] = 0;
636 text.UngetWriteBuf();
641 if (success && addToMemoryFS)
642 wxMemoryFSHandler::AddFile(filename, text);
647 // Get a text resource from the memory filesystem
648 bool ecApp::GetMemoryTextResource(const wxString& filename, wxString& text)
650 wxString s(wxString(wxT("memory:")) + filename);
651 wxFSFile* file = wxGetApp().GetFileSystem()->OpenFile(s);
654 wxInputStream* stream = file->GetStream();
656 char* buf = text.GetWriteBuf(stream->GetSize() + 1);
657 stream->Read((void*) buf, stream->GetSize());
658 buf[stream->GetSize()] = 0;
659 text.UngetWriteBuf();
668 // Version-stamp the splash screen
669 bool ecApp::VersionStampSplashScreen()
671 if (m_splashScreenBitmap.Ok())
674 dc.SelectObject(m_splashScreenBitmap);
676 wxColour textColour(19, 49, 4);
677 dc.SetTextForeground(textColour);
678 dc.SetBackgroundMode(wxTRANSPARENT);
679 dc.SetFont(wxFont(11, wxSWISS, wxNORMAL, wxBOLD, FALSE));
681 // Bottom left of area to start drawing at
684 verString.Printf("%s", ecCONFIGURATION_TOOL_VERSION);
686 int x = 339; int y = 231;
688 y += 5; // For some reason
691 dc.GetTextExtent(verString, & w, & h);
692 dc.DrawText(verString, x, y - h);
694 dc.SelectObject(wxNullBitmap);
702 // Initialize window settings object
703 bool ecApp::InitializeWindowSettings(bool beforeWindowConstruction)
705 wxWindowSettings& settings = GetSettings().m_windowSettings;
706 ecMainFrame* frame = GetMainFrame();
708 if (beforeWindowConstruction)
710 settings.Add(wxT("Configuration"));
711 settings.Add(wxT("Short Description"));
712 settings.Add(wxT("Output"));
713 settings.Add(wxT("Properties"));
714 settings.Add(wxT("Conflicts"));
719 arr.Add(frame->GetTreeCtrl());
720 arr.Add(frame->GetValueWindow());
721 settings.SetWindows(wxT("Configuration"), arr);
723 settings.SetWindow(wxT("Short Description"), frame->GetShortDescriptionWindow());
724 settings.SetWindow(wxT("Output"), frame->GetOutputWindow());
725 settings.SetWindow(wxT("Properties"), frame->GetPropertyListWindow());
726 settings.SetWindow(wxT("Conflicts"), frame->GetConflictsWindow());
733 bool ecApp::InitializeHelpController()
735 if (m_helpController)
736 delete m_helpController;
737 m_helpController = new wxHelpController;
739 if (!m_helpController->Initialize(GetHelpFile()))
746 // Tell the help controller where the repository documentation is.
747 // For now, just keep this to myself since it uses hacks to wxWin
748 ecConfigToolDoc* doc = GetConfigToolDoc();
750 // No longer using relative paths
754 wxString htmlDir = wxString(doc->GetRepository()) + wxString(wxT("/doc/html"));
755 if (!wxDirExists(htmlDir))
756 htmlDir = wxString(doc->GetRepository()) + wxString(wxT("/doc"));
758 htmlDir += wxString(wxT("/"));
760 wxGetApp().GetHelpController().SetBookBasePath(htmlDir);
767 // Check if there is a (unique) .ecc file in dir
768 bool ecApp::FindSaveFileInDir(const wxString& dir, wxString& saveFile)
772 if (!fileFind.Open(dir))
775 wxString wildcard = wxT(".ecc");
778 bool found = fileFind.GetFirst (& filename, wildcard);
781 // Fail if there was more than one matching file.
783 if (fileFind.GetNext (& filename2))
787 saveFile = dir + wxString(wxFILE_SEP_PATH) + filename;
794 int ecApp::OnExit(void)
797 if (m_helpController)
799 delete m_helpController;
800 m_helpController = NULL;
806 m_splashScreen->Destroy();
807 m_splashScreen = NULL;
810 m_settings.SaveConfig();
813 wxConfig config(wxGetApp().GetSettings().GetConfigAppName());
814 if (config.HasGroup(wxT("FileHistory")))
815 config.DeleteGroup(wxT("FileHistory"));
816 config.SetPath(wxT("FileHistory/"));
817 m_docManager->FileHistorySave(config);
825 // Prepend the current program directory to the name
826 wxString ecApp::GetFullAppPath(const wxString& filename) const
828 wxString path(m_appDir);
829 if (path.Last() != '\\' && path.Last() != '/' && filename[0] != '\\' && filename[0] != '/')
840 // Are we running in 32K colours or more?
841 bool ecApp::GetHiColour() const
843 static bool hiColour = (wxDisplayDepth() >= 16) ;
847 // General handler for 'What's this?'
848 void ecApp::OnWhatsThis(wxCommandEvent& event)
850 wxObject* obj = event.GetEventObject();
851 wxWindow* win = NULL;
853 if (obj->IsKindOf(CLASSINFO(wxMenu)))
855 win = ((wxMenu*) obj)->GetInvokingWindow();
857 else if (obj->IsKindOf(CLASSINFO(wxWindow)))
859 win = (wxWindow*) obj;
862 wxWindow* subjectOfHelp = win;
863 bool eventProcessed = FALSE;
864 wxPoint pt = wxGetMousePosition();
866 while (subjectOfHelp && !eventProcessed)
868 wxHelpEvent helpEvent(wxEVT_HELP, subjectOfHelp->GetId(), pt) ;
869 helpEvent.SetEventObject(this);
870 eventProcessed = win->GetEventHandler()->ProcessEvent(helpEvent);
872 // Go up the window hierarchy until the event is handled (or not).
873 // I.e. keep submitting ancestor windows until one is recognised
874 // by the app code that processes the ids and displays help.
875 subjectOfHelp = subjectOfHelp->GetParent();
877 // wxGetApp().GetHelpController().DisplayTextPopup(GetHelpText(), wxGetMousePosition());
880 // Log to output window
881 void ecApp::Log(const wxString& msg)
883 ecMainFrame* frame = (ecMainFrame*) GetTopWindow();
886 frame->GetOutputWindow()->AppendText(msg /* + wxT("\n") */ );
887 if ((msg == wxEmptyString) || (msg.Last() != wxT('\n')))
888 frame->GetOutputWindow()->AppendText(wxT("\n"));
890 // frame->GetOutputWindow()->ShowPosition(frame->GetOutputWindow()->GetLastPosition());
894 void ecApp::SetStatusText(const wxString& text, bool clearFailingRulesPane)
896 ecMainFrame* mainFrame = GetMainFrame();
899 mainFrame->GetStatusBar()->SetStatusText(text, ecStatusPane);
900 if (clearFailingRulesPane)
901 mainFrame->GetStatusBar()->SetStatusText(wxT(""), ecFailRulePane);
903 ::UpdateWindow((HWND) mainFrame->GetHWND());
909 // Config tree control
910 ecConfigTreeCtrl* ecApp::GetTreeCtrl() const
912 return GetMainFrame()->GetTreeCtrl();
916 ecMemoryLayoutWindow* ecApp::GetMLTWindow() const
918 return GetMainFrame()->GetMemoryLayoutWindow();
921 // Get active document
922 ecConfigToolDoc* ecApp::GetConfigToolDoc() const
930 return wxDynamicCast(m_docManager->GetCurrentDocument(), ecConfigToolDoc);
933 bool ecApp::Launch(const wxString & strFileName,const wxString &strViewer)
938 if (!strViewer.IsEmpty())
940 cmd = strViewer + wxString(wxT(" ")) + strFileName ;
944 wxString path, filename, ext;
945 wxSplitPath(strFileName, & path, & filename, & ext);
947 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
950 wxLogError(_T("Impossible to determine the file type for extension '%s'"),
955 bool ok = ft->GetOpenCommand(&cmd,
956 wxFileType::MessageParameters(strFileName, _T("")));
961 // TODO: some kind of configuration dialog here.
962 wxMessageBox(_("Could not determine the command for opening this file."),
963 wxGetApp().GetSettings().GetAppName(), wxOK|wxICON_EXCLAMATION);
968 ok = (wxExecute(cmd, FALSE) != 0);
975 if(!strViewer.IsEmpty())//use custom editor
977 CString strCmdline(strViewer);
979 TCHAR *pszCmdLine=strCmdline.GetBuffer(strCmdline.GetLength());
980 GetShortPathName(pszCmdLine,pszCmdLine,strCmdline.GetLength());
981 strCmdline.ReleaseBuffer();
983 strCmdline+=_TCHAR(' ');
984 strCmdline+=strFileName;
985 PROCESS_INFORMATION pi;
988 si.cb = sizeof(STARTUPINFO);
989 si.lpReserved = NULL;
990 si.lpReserved2 = NULL;
998 //strCmdline.GetBuffer(strCmdline.GetLength()), // command line
999 strCmdline.GetBuffer(strCmdline.GetLength()), // command line
1000 NULL, // process security
1001 NULL, // thread security
1002 TRUE, // inherit handles
1004 NULL, // environment
1005 NULL, // current dir
1006 &si, // startup info
1008 CloseHandle(pi.hProcess);
1009 CloseHandle(pi.hThread);
1012 CUtils::MessageBoxF(_T("Failed to invoke %s.\n"),strCmdline);
1014 strCmdline.ReleaseBuffer();
1015 } else {// Use association
1016 TCHAR szExe[MAX_PATH];
1017 HINSTANCE h=FindExecutable(strFileName,_T("."),szExe);
1021 case 0: str=_T("The system is out of memory or resources.");break;
1022 case 31: str=_T("There is no association for the specified file type.");break;
1023 case ERROR_FILE_NOT_FOUND: str=_T("The specified file was not found.");break;
1024 case ERROR_PATH_NOT_FOUND: str=_T("The specified path was not found.");break;
1025 case ERROR_BAD_FORMAT: str=_T("The .EXE file is invalid (non-Win32 .EXE or error in .EXE image).");break;
1028 CUtils::MessageBoxF(_T("Failed to open document %s.\r\n%s"),strFileName,str);
1031 SHELLEXECUTEINFO sei = {sizeof(sei), 0, AfxGetMainWnd()->GetSafeHwnd(), _T("open"),
1032 strFileName, NULL, NULL, SW_SHOWNORMAL, AfxGetInstanceHandle( )};
1035 HINSTANCE hInst=ShellExecute(AfxGetMainWnd()->GetSafeHwnd(),_T("open"), strFileName, NULL, _T("."), 0)/*ShellExecuteEx(&sei)*/;
1036 if(int(hInst)<=32/*sei.hInstApp==0*/)
1041 case 0 : str=_T("The operating system is out of memory or resources. ");break;
1042 case ERROR_FILE_NOT_FOUND : str=_T("The specified file was not found. ");break;
1043 case ERROR_PATH_NOT_FOUND : str=_T("The specified path was not found. ");break;
1044 case ERROR_BAD_FORMAT : str=_T("The .EXE file is invalid (non-Win32 .EXE or error in .EXE image). ");break;
1045 case SE_ERR_ACCESSDENIED : str=_T("The operating system denied access to the specified file. ");break;
1046 case SE_ERR_ASSOCINCOMPLETE : str=_T("The filename association is incomplete or invalid. ");break;
1047 case SE_ERR_DDEBUSY : str=_T("The DDE transaction could not be completed because other DDE transactions were being processed. ");break;
1048 case SE_ERR_DDEFAIL : str=_T("The DDE transaction failed. ");break;
1049 case SE_ERR_DDETIMEOUT : str=_T("The DDE transaction could not be completed because the request timed out. ");break;
1050 case SE_ERR_DLLNOTFOUND : str=_T("The specified dynamic-link library was not found. ");break;
1051 //case SE_ERR_FNF : str=_T("The specified file was not found. ");break;
1052 case SE_ERR_NOASSOC : str=_T("There is no application associated with the given filename extension. ");break;
1053 case SE_ERR_OOM : str=_T("There was not enough memory to complete the operation. ");break;
1054 //case SE_ERR_PNF : str=_T("The specified path was not found. ");break;
1055 case SE_ERR_SHARE : str=_T("A sharing violation occurred. ");break;
1056 default: str=_T("An unexpected error occurred");break;
1058 CUtils::MessageBoxF(_T("Failed to open document %s using %s.\r\n%s"),strFileName,szExe,str);
1068 bool ecApp::PrepareEnvironment(bool bWithBuildTools, wxString* cmdLine)
1071 // Under Windows we can set variables.
1072 ecConfigToolDoc *pDoc = GetConfigToolDoc();
1074 wxSetEnv(wxT("PATH"), m_strOriginalPath);
1076 const wxString strPrefix(pDoc->GetCurrentTargetPrefix());
1077 ecFileName strBinDir;
1080 rc=(! bWithBuildTools) || GetSettings().m_arstrBinDirs.Find(strPrefix, strBinDir);
1083 // Use fallback of previously-entered build tools directory, if available
1084 if (!GetSettings().m_buildToolsDir.IsEmpty())
1086 strBinDir = GetSettings().m_buildToolsDir ;
1091 wxCommandEvent event;
1092 GetMainFrame()->OnBuildToolsPath(event);
1093 rc = GetSettings().m_arstrBinDirs.Find(strPrefix, strBinDir);
1099 ecFileName strUserBinDir(GetSettings().m_userToolsDir);
1100 if(strUserBinDir.IsEmpty())
1102 if ( 1 == GetSettings().m_userToolPaths.GetCount() )
1104 GetSettings().m_userToolsDir = GetSettings().m_userToolPaths[0];
1107 wxCommandEvent event;
1108 GetMainFrame()->OnUserToolsPath(event);
1110 strUserBinDir = GetSettings().m_userToolsDir;
1112 if ( !strUserBinDir.IsEmpty() )
1114 // calculate the directory of the host tools from this application's module name
1115 ecFileName strHostToolsBinDir(this->argv[0]);
1116 strHostToolsBinDir = strHostToolsBinDir.Head ();
1118 // tools directories are in the order host-tools, user-tools, comp-tools, install/bin (if present), contrib-tools (if present) on the path
1119 const ecFileName strContribBinDir(strUserBinDir, wxT("..\\contrib\\bin"));
1120 ecFileName strUsrBinDir(strUserBinDir, wxT("..\\usr\\bin"));
1121 const ecFileName strInstallBinDir(pDoc->GetInstallTree (), wxT("bin"));
1123 // In case strUserBinDir is e.g. c:\program files\red hat\cygwin-00r1\usertools\h-i686-pc-cygwin\bin
1124 if (!strUsrBinDir.IsDir ())
1125 strUsrBinDir = ecFileName(strUserBinDir + _T("..\\..\\..\\H-i686-pc-cygwin\\bin"));
1128 (strUsrBinDir.IsDir () && ! ecUtils::AddToPath (strUsrBinDir)) ||
1129 (strContribBinDir.IsDir () && ! ecUtils::AddToPath (strContribBinDir)) ||
1130 (strInstallBinDir.IsDir () && ! ecUtils::AddToPath (strInstallBinDir)) ||
1131 (bWithBuildTools && ! ecUtils::AddToPath (strBinDir)) ||
1132 ! ecUtils::AddToPath (strUserBinDir) ||
1133 ! ecUtils::AddToPath (strHostToolsBinDir))
1136 msg.Printf(wxT("Failed to set PATH environment variable"));
1137 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
1141 if(!wxSetEnv(_T("MAKE_MODE"),_T("unix")))
1144 msg.Printf(wxT("Failed to set MAKE_MODE environment variable"));
1145 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
1149 // Remove from the environment
1150 wxUnsetEnv(wxT("GDBTK_LIBRARY"));
1151 wxUnsetEnv(wxT("GCC_EXEC_PREFIX"));
1153 // Useful for ecosconfig
1154 wxSetEnv(wxT("ECOS_REPOSITORY"), pDoc->GetPackagesDir());
1156 // Mount /ecos-x so we can access these in text mode
1157 if (! pDoc->GetBuildTree().IsEmpty() && wxIsalpha(pDoc->GetBuildTree()[0]))
1158 CygMount(pDoc->GetBuildTree()[0]);
1159 if (! pDoc->GetInstallTree().IsEmpty() && wxIsalpha(pDoc->GetInstallTree()[0]))
1160 CygMount(pDoc->GetInstallTree()[0]);
1161 if (! pDoc->GetRepository().IsEmpty() && wxIsalpha(pDoc->GetRepository()[0]))
1162 CygMount(pDoc->GetRepository()[0]);
1169 wxASSERT ( cmdLine != NULL );
1171 (* cmdLine) = wxEmptyString;
1173 // Under Unix we need to build up a command line to set variables and invoke make
1174 ecConfigToolDoc *pDoc = GetConfigToolDoc();
1176 const wxString strPrefix(pDoc->GetCurrentTargetPrefix());
1177 ecFileName strBinDir;
1180 rc=(! bWithBuildTools) || GetSettings().m_arstrBinDirs.Find(strPrefix, strBinDir);
1183 // Use fallback of previously-entered build tools directory, if available
1184 if (!GetSettings().m_buildToolsDir.IsEmpty())
1186 strBinDir = GetSettings().m_buildToolsDir ;
1191 wxCommandEvent event;
1192 GetMainFrame()->OnBuildToolsPath(event);
1193 rc = GetSettings().m_arstrBinDirs.Find(strPrefix, strBinDir);
1199 if (!strBinDir.IsEmpty())
1201 (* cmdLine) += wxString(wxT("export PATH=")) + wxString(strBinDir) + wxT(":$PATH; ");
1203 // Also set the path
1204 wxString oldPath(wxGetenv(wxT("PATH")));
1205 wxString path(strBinDir);
1206 if (!oldPath.IsEmpty())
1211 wxSetEnv(wxT("PATH"), path);
1213 (* cmdLine) += wxString(wxT("unset GDBTK_LIBRARY; ")) ;
1214 wxUnsetEnv(wxT("GDBTK_LIBRARY"));
1216 (* cmdLine) += wxString(wxT("unset GCC_EXEC_PREFIX; ")) ;
1217 wxUnsetEnv(wxT("GCC_EXEC_PREFIX"));
1219 (* cmdLine) += wxString(wxT("export ECOS_REPOSITORY=")) + wxString(pDoc->GetPackagesDir()) + wxT("; ");
1220 wxSetEnv(wxT("ECOS_REPOSITORY"), pDoc->GetPackagesDir());
1223 ecFileName strUserBinDir(GetSettings().m_userToolsDir);
1224 if(strUserBinDir.IsEmpty())
1226 if ( 1 == GetSettings().m_userToolPaths.GetCount() )
1228 GetSettings().m_userToolsDir = GetSettings().m_userToolPaths[0];
1231 wxCommandEvent event;
1232 GetMainFrame()->OnUserToolsPath(event);
1234 strUserBinDir = GetSettings().m_userToolsDir;
1236 if ( !strUserBinDir.IsEmpty() )
1238 // calculate the directory of the host tools from this application's module name
1239 ecFileName strHostToolsBinDir(this->argv[0]);
1240 strHostToolsBinDir = strHostToolsBinDir.Head ();
1242 // tools directories are in the order host-tools, user-tools, comp-tools, install/bin (if present), contrib-tools (if present) on the path
1244 // TODO: is this right? Assuming that the user tools are already in the user's path.
1245 // const ecFileName strContribBinDir(strUserBinDir, wxT("..\\contrib\\bin"));
1246 // const ecFileName strUsrBinDir(strUserBinDir, wxT("..\\usr\\bin"));
1247 const ecFileName strInstallBinDir(pDoc->GetInstallTree (), wxT("bin"));
1249 (* cmdLine) += wxString(wxT("export PATH=")) + wxString(strInstallBinDir) + wxT(":$PATH; ");
1250 (* cmdLine) += wxString(wxT("unset GDBTK_LIBRARY; ")) ;
1251 (* cmdLine) += wxString(wxT("unset GCC_EXEC_PREFIX; ")) ;
1252 (* cmdLine) += wxString(wxT("export ECOS_REPOSITORY=")) + wxString(pDoc->GetPackagesDir()) + wxT("; ");
1260 void ecApp::CygMount(wxChar c)
1262 // May not be alpha if it's e.g. a UNC network path
1268 if(!sm_arMounted[c-_TCHAR('a')])
1270 sm_arMounted[c-wxChar('a')]=true;
1274 strCmd.Printf(wxT("mount -t -u %c: /ecos-%c"),c,c);
1276 sub.Run(strOutput,strCmd);
1280 // Doing it with wxExecute results in a flashing DOS box unfortunately
1282 wxASSERT(wxIsalpha(c));
1284 if(!sm_arMounted[c-wxChar('a')])
1286 sm_arMounted[c-wxChar('a')] = TRUE;
1289 strCmd.Printf(wxT("mount.exe %c: /%c"),c,c);
1291 wxExecute(strCmd, TRUE);
1296 // Fiddling directly with the registry DOESN'T WORK because Cygwin mount tables
1297 // get out of synch with the registry
1298 void ecApp::CygMountText(wxChar c)
1300 wxASSERT(wxIsalpha(c));
1302 // if(!sm_arMounted[c-wxChar('a')])
1304 // sm_arMounted[c-wxChar('a')] = TRUE;
1309 strCmd.Printf(wxT("mount.exe %c: /ecos-%c"),c,c);
1311 wxExecute(strCmd, TRUE);
1313 wxString key, value;
1314 key.Printf(wxT("/ecos-%c"), c);
1315 value.Printf(wxT("%c:"), c);
1317 // Mount by fiddling with registry instead, so we don't see ugly flashing windows
1320 if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Cygnus Solutions\\Cygwin\\mounts v2",
1321 0, KEY_READ, &hKey))
1326 if (ERROR_SUCCESS == RegCreateKeyEx(hKey, key, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
1327 NULL, & hSubKey, & disposition))
1329 RegSetValueEx(hSubKey, "native", 0, REG_SZ, (unsigned char*) (const wxChar*) value, value.Length() + 1);
1330 RegCloseKey(hSubKey);
1341 void ecApp::Build(const wxString &strWhat /*=wxT("")*/ )
1346 ecConfigToolDoc* pDoc = GetConfigToolDoc();
1350 if (!wxGetApp().GetMainFrame()->GetOutputWindow()->IsShown())
1352 wxGetApp().GetMainFrame()->ToggleWindow(ecID_TOGGLE_OUTPUT);
1354 if (!pDoc->GetDocumentSaved())
1359 if (pDoc->IsModified() && !wxDirExists(pDoc->GetBuildTree()))
1364 // if ( !(pDoc->IsModified() || !wxDirExists(pDoc->GetBuildTree())) ) // verify the save worked
1365 if ( pDoc->GetDocumentSaved() )
1367 //wxString strCmd (wxT("c:\\bin\\testmake.bat"));
1368 wxString strCmd (wxT("make"));
1369 if(!strWhat.IsEmpty())
1375 if(!GetSettings().m_strMakeOptions.IsEmpty())
1378 strCmd += GetSettings().m_strMakeOptions;
1380 strCmd += wxT(" --directory ");
1382 // Quoting the name may not mix with the 'sh' command on Unix, so only do it
1383 // under Windows where it's more likely there will be spaces needing quoting.
1385 wxString buildDir(pDoc->GetBuildTree());
1387 #if ecUSE_ECOS_X_NOTATION
1388 std::string cPath = cygpath(std::string(pDoc->GetBuildTree()));
1389 buildDir = cPath.c_str();
1391 strCmd += wxString(wxT("\"")) + buildDir + wxString(wxT("\""));
1393 strCmd += wxString(pDoc->GetBuildTree()) ;
1396 wxString variableSettings;
1398 if (PrepareEnvironment(TRUE, & variableSettings))
1401 // strCmd is all we need
1403 // strCmd has to invoke a shell with variables and make invocation
1404 strCmd = wxString(wxT("sh -c \"")) + variableSettings + strCmd + wxString(wxT("\""));
1406 // Output the command so we know what we're doing
1410 // No: pass --directory
1411 // wxSetWorkingDirectory(pDoc->GetBuildTree());
1413 m_pipedProcess = new ecPipedProcess;
1414 long pid = wxExecute(strCmd, FALSE, m_pipedProcess);
1417 m_pipedProcess->SetPid(pid);
1418 // wxLogStatus(_T("Process %ld (%s) launched."), pid, cmd.c_str());
1422 wxLogError(_T("Execution of '%s' failed."), strCmd.c_str());
1424 delete m_pipedProcess;
1425 m_pipedProcess = NULL;
1430 if(PrepareEnvironment())
1432 m_strBuildTarget=strWhat;
1433 SetThermometerMax(250); // This is just a guess. The thread we are about to spawn will work out the correct answer
1435 UpdateThermometer(0);
1436 CloseHandle(CreateThread(NULL, 0, ThreadFunc, this, 0 ,&m_dwThreadId));
1438 strMsg.Format(_T("Building %s"),strWhat);
1439 SetIdleMessage(strMsg);
1441 SetTimer(42,1000,0); // This timer checks for process completion
1442 SetCurrentDirectory(pDoc->BuildTree());
1443 m_sp.Run(SubprocessOutputFunc, this, strCmd, false);
1450 if(pDoc->IsModified()||pDoc->BuildTree().IsEmpty()){
1451 SendMessage (WM_COMMAND, ID_FILE_SAVE);
1454 if(!(pDoc->IsModified()||pDoc->BuildTree().IsEmpty())){ // verify the save worked
1455 CString strCmd (_T("make"));
1456 if(!strWhat.IsEmpty()){
1457 strCmd+=_TCHAR(' ');
1460 if(!GetApp()->m_strMakeOptions.IsEmpty()){
1461 strCmd+=_TCHAR(' ');
1462 strCmd+=GetApp()->m_strMakeOptions;
1465 if(PrepareEnvironment()){
1466 m_strBuildTarget=strWhat;
1467 SetThermometerMax(250); // This is just a guess. The thread we are about to spawn will work out the correct answer
1469 UpdateThermometer(0);
1470 CloseHandle(CreateThread(NULL, 0, ThreadFunc, this, 0 ,&m_dwThreadId));
1472 strMsg.Format(_T("Building %s"),strWhat);
1473 SetIdleMessage(strMsg);
1475 SetTimer(42,1000,0); // This timer checks for process completion
1476 SetCurrentDirectory(pDoc->BuildTree());
1477 m_sp.Run(SubprocessOutputFunc, this, strCmd, false);
1484 void ecApp::OnProcessTerminated(wxProcess* process)
1486 m_pipedProcess = NULL;
1489 // ----------------------------------------------------------------------------
1491 // ----------------------------------------------------------------------------
1493 bool ecPipedProcess::HasInput()
1495 bool hasInput = FALSE;
1497 wxInputStream& is = *GetInputStream();
1498 if ( IsInputAvailable() )
1500 wxTextInputStream tis(is);
1502 // this assumes that the output is always line buffered
1504 msg << tis.ReadLine();
1506 wxGetApp().Log(msg);
1511 wxInputStream& es = *GetErrorStream();
1512 if ( IsErrorAvailable() )
1514 wxTextInputStream tis(es);
1516 // this assumes that the output is always line buffered
1518 msg << tis.ReadLine();
1520 wxGetApp().Log(msg);
1528 void ecPipedProcess::OnTerminate(int pid, int status)
1530 // show the rest of the output
1531 while ( HasInput() )
1534 wxGetApp().OnProcessTerminated(this);
1536 //wxLogStatus(m_parent, _T("Process %u ('%s') terminated with exit code %d."),
1537 // pid, m_cmd.c_str(), status);
1539 // we're not needed any more
1543 void ecPingTimer::Notify()
1545 static bool s_inNotify = FALSE;
1552 // On Windows, simply having the timer going will ping the message queue
1553 // and cause idle processing to happen.
1554 // On Unix, this doesn't happen so we have to do the processing explicitly.
1559 if ( wxGetApp().m_pipedProcess )
1560 while (wxGetApp().m_pipedProcess->HasInput())
1562 // Loop while there is still input