unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / tools / src / tools / configtool / standalone / wxwin / configtool.cpp
1 //####COPYRIGHTBEGIN####
2 //
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
5 // Copyright (C) 2003 John Dallaway
6 //
7 // This program is part of the eCos host tools.
8 //
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)
12 // any later version.
13 //
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
17 // more details.
18 //
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.
22 //
23 // ----------------------------------------------------------------------------
24 //
25 //####COPYRIGHTEND####
26 // configtool.cpp :
27 //
28 //===========================================================================
29 //#####DESCRIPTIONBEGIN####
30 //
31 // Author(s):   julians, jld
32 // Contact(s):  julians, jld
33 // Date:        2000/08/24
34 // Version:     $Id$
35 // Purpose:
36 // Description: Implementation file for the ConfigTool application class
37 // Requires:
38 // Provides:
39 // See also:
40 // Known bugs:
41 // Usage:
42 //
43 //####DESCRIPTIONEND####
44 //
45 //===========================================================================
46
47 // ============================================================================
48 // declarations
49 // ============================================================================
50
51 // ----------------------------------------------------------------------------
52 // headers
53 // ----------------------------------------------------------------------------
54 #ifdef __GNUG__
55     #pragma implementation "configtool.h"
56 #endif
57
58 // Includes other headers for precompiled compilation
59 #include "ecpch.h"
60
61 #ifdef __BORLANDC__
62     #pragma hdrstop
63 #endif
64
65 #include "eCosSocket.h"
66 #include "eCosTestPlatform.h"
67
68 #include "wx/splash.h"
69 #include "wx/cshelp.h"
70 #include "wx/image.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"
80
81 #include "configtool.h"
82 #include "configtoolview.h"
83 #include "configtree.h"
84 #include "mainwin.h"
85 #include "outputwin.h"
86 #include "configtooldoc.h"
87 #include "aboutdlg.h"
88 #include "shortdescrwin.h"
89 #include "conflictwin.h"
90 #include "propertywin.h"
91 #include "symbols.h"
92 #include "build.hxx"
93 #include "Subprocess.h"
94
95 // ----------------------------------------------------------------------------
96 // resources
97 // ----------------------------------------------------------------------------
98 // the application icon
99 #if defined(__WXGTK__) || defined(__WXMOTIF__)
100     #include "bitmaps/configtool.xpm"
101 #endif
102
103 // Create a new application object.
104 IMPLEMENT_APP(ecApp)
105
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)
109 END_EVENT_TABLE()
110
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};
112
113 static const wxCmdLineEntryDesc sg_cmdLineDesc[] =
114 {
115 /*
116     { wxCMD_LINE_SWITCH, "v", "verbose", "be verbose" },
117     { wxCMD_LINE_SWITCH, "q", "quiet",   "be quiet" },
118
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 },
123 */
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" },
128
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 },
131
132     { wxCMD_LINE_NONE }
133 };
134
135 ecApp::ecApp()
136 {
137     m_docManager = NULL;
138     m_mainFrame = NULL;
139     m_currentDoc = NULL;
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;
145     m_valuesLocked = 0;
146     m_helpController = NULL;
147     m_fileSystem = new wxFileSystem;
148 #if wxUSE_STREAMS && wxUSE_ZIPSTREAM && wxUSE_ZLIB
149     m_zipHandler = new wxZipFSHandler;
150 #endif
151 }
152
153 ecApp::~ecApp()
154 {
155     delete m_whatsThisMenu;
156     delete m_fileSystem;
157 }
158
159 // 'Main program' equivalent: the program execution "starts" here
160 bool ecApp::OnInit()
161 {
162     wxLog::SetTimestamp(NULL);
163
164     CeCosSocket::Init();
165     CeCosTestPlatform::Load();
166
167     wxHelpProvider::Set(new wxSimpleHelpProvider);
168     //wxHelpProvider::Set(new wxHelpControllerHelpProvider(& m_helpController));
169
170     wxImage::AddHandler(new wxPNGHandler);
171     wxImage::AddHandler(new wxGIFHandler);
172
173     // Required for advanced HTML help
174 #if wxUSE_STREAMS && wxUSE_ZIPSTREAM && wxUSE_ZLIB
175     wxFileSystem::AddHandler(m_zipHandler);
176 #endif
177
178     // Mandatory initialisation for Tcl 8.4
179     Tcl_FindExecutable(argv[0]);
180
181     wxString currentDir = wxGetCwd();
182
183     // Use argv to get current app directory
184     m_appDir = wxFindAppPath(argv[0], currentDir, wxT("CONFIGTOOLDIR"));
185     
186     // If the development version, go up a directory.
187 #ifdef __WXMSW__
188     if ((m_appDir.Right(5).CmpNoCase("DEBUG") == 0) ||
189         (m_appDir.Right(11).CmpNoCase("DEBUGSTABLE") == 0) ||
190         (m_appDir.Right(7).CmpNoCase("RELEASE") == 0) ||
191         (m_appDir.Right(13).CmpNoCase("RELEASESTABLE") == 0)
192         )
193         m_appDir = wxPathOnly(m_appDir);
194 #endif
195
196     // Load resources from binary resources archive, or failing that, from
197     // Windows resources or plain files
198     LoadResources();
199
200     wxGetEnv(wxT("PATH"), & m_strOriginalPath);
201
202     // Create a document manager
203     m_docManager = new wxDocManager;
204
205     // Create a template relating documents to their views
206     wxDocTemplate* templ = new wxDocTemplate(m_docManager, "Configtool", "*.ecc", "", "ecc", "Configtool Doc", "Configtool View",
207         CLASSINFO(ecConfigToolDoc), CLASSINFO(ecConfigToolView));
208
209     // If we've only got one window, we only get to edit
210     // one document at a time.
211     m_docManager->SetMaxDocsOpen(1);
212     
213     // Initialize config settings
214     m_settings.Init();
215
216     // Let wxWindows know what the app name is
217     SetAppName(m_settings.GetAppName());
218
219     InitializeWindowSettings(TRUE /* beforeWindowConstruction */) ;
220
221     // Load config settings
222     m_settings.LoadConfig();
223
224     // Set the default directory for opening/saving files
225     if (!m_settings.m_lastFilename.IsEmpty())
226         templ->SetDirectory(wxPathOnly(m_settings.m_lastFilename));
227
228     // Parse the command-line parameters and options
229     wxCmdLineParser parser(sg_cmdLineDesc, argc, argv);
230     int res;
231     {
232         wxLogNull log;
233         res = parser.Parse();
234     }
235     if (res == -1 || res > 0 || parser.Found(wxT("h")))
236     {
237 #ifdef __WXGTK__
238         wxLog::SetActiveTarget(new wxLogStderr);
239 #endif
240         parser.Usage();
241         return FALSE;
242     }
243     if (parser.Found(wxT("v")))
244     {
245 #ifdef __WXGTK__
246         wxLog::SetActiveTarget(new wxLogStderr);
247 #endif
248         wxString msg;
249         msg.Printf(wxT("eCos Configuration Tool (c) Red Hat, 2001 Version %.2f, %s"), ecCONFIGURATION_TOOL_VERSION, __DATE__);
250         wxLogMessage(msg);
251         return FALSE;
252     }
253
254 /*
255 #ifdef __WXMSW__
256     wxBitmap bitmap(wxBITMAP(splash));
257 #else
258     wxBitmap bitmap;
259     if (wxFileExists("splash16.png"))
260         bitmap.LoadFile("splash16.png", wxBITMAP_TYPE_PNG);
261 #endif
262 */
263
264     //    wxYieldIfNeeded();
265
266     // create the main application window
267     ecMainFrame *frame = new ecMainFrame(m_docManager, GetSettings().GetAppName(),
268         wxPoint(GetSettings().m_frameSize.x, GetSettings().m_frameSize.y),
269         wxSize(GetSettings().m_frameSize.width, GetSettings().m_frameSize.height));
270
271     m_mainFrame = frame;
272     SetTopWindow(frame);
273     frame->Show(TRUE);
274     SendIdleEvents(); // Otherwise UI updates aren't done, because it's busy loading the repository
275 #ifdef __WXMSW__
276     ::UpdateWindow((HWND) frame->GetHWND());
277 #endif
278
279     InitializeWindowSettings(FALSE /* beforeWindowConstruction */) ;
280
281     if (m_splashScreenBitmap.Ok() && GetSettings().m_showSplashScreen)
282     {
283         m_splashScreen = new ecSplashScreen(m_splashScreenBitmap, wxSPLASH_CENTRE_ON_SCREEN|wxSPLASH_TIMEOUT,
284             5000, NULL, -1, wxDefaultPosition, wxDefaultSize, wxNO_BORDER|wxFRAME_FLOAT_ON_PARENT|wxSTAY_ON_TOP);
285     }
286
287     //    if (m_splashScreen)
288     //        m_splashScreen->Raise();
289
290     wxYieldIfNeeded();
291
292     if (parser.Found(wxT("e")))
293         GetSettings().m_editSaveFileOnly = TRUE;
294
295     // If in --compile-help (-c) mode, then exit immediately after recompiling help file
296     bool compileHelpOnly = parser.Found(wxT("c"));
297
298     wxString filenameToOpen1, filenameToOpen2;
299     if (parser.GetParamCount() > 0)
300     {
301         wxString tmpSaveFile;
302
303         filenameToOpen1 = parser.GetParam(0);
304
305         if (parser.GetParamCount() > 1)
306             filenameToOpen2 = parser.GetParam(1);
307
308         bool gotRepository = FALSE;
309         bool gotSavefile = FALSE;
310
311         wxString repositoryDir, saveFile;
312
313         // Might be e.g. . or .. in path, or relative path
314         filenameToOpen1 = wxGetRealPath(currentDir, filenameToOpen1);
315
316         if (parser.GetParamCount() > 1)
317             filenameToOpen2 = wxGetRealPath(currentDir, filenameToOpen2);
318
319         wxString path1, name1, ext1;
320         wxSplitPath(filenameToOpen1, & path1, & name1, & ext1);
321
322         wxString path2, name2, ext2;
323         wxSplitPath(filenameToOpen2, & path2, & name2, & ext2);
324
325         // Look at the first file
326         if (ext1 == "ecc" || ext1 == "ECC")
327         {
328             if (wxFileExists(filenameToOpen1))
329             {
330                 gotSavefile = TRUE;
331                 saveFile = filenameToOpen1;
332             }
333             else
334             {
335                 wxString msg;
336                 msg.Printf("%s is not a valid file.", (const wxChar*) filenameToOpen1);
337                 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
338                 return FALSE;
339             }
340         }
341         else if (wxDirExists(filenameToOpen1) && FindSaveFileInDir(filenameToOpen1, tmpSaveFile))
342         {
343             saveFile = tmpSaveFile;
344             gotSavefile = TRUE;
345         }
346         else if ((name1 == wxT("ecos") && ext1 == wxT("db") && wxFileExists(filenameToOpen1)) || wxDirExists(filenameToOpen1))
347         {
348             // It's a repository (we hope).
349             if (name1 == wxT("ecos") && ext1 == wxT("db"))
350             {
351                 // Go two steps up
352                 filenameToOpen1 = wxPathOnly(filenameToOpen1);
353                 filenameToOpen1 = wxPathOnly(filenameToOpen1);
354             }
355             else
356             {
357                 // If it's the packages directory, we need to strip off
358                 // a directory
359                 wxString eccPath(filenameToOpen1 + wxString(wxFILE_SEP_PATH) + wxT("ecc"));
360
361                 // Don't strip off ecc if it's the CVS repository (with ecc below it)
362                 if (name1 == wxT("packages") || (name1 == wxT("ecc") && !wxDirExists(eccPath)))
363                     filenameToOpen1 = wxPathOnly(filenameToOpen1);
364             }
365
366             repositoryDir = filenameToOpen1;
367             gotRepository = TRUE;
368         }
369         else
370         {
371             wxString msg;
372             msg.Printf("%s is neither a project file nor a valid repository.", (const wxChar*) filenameToOpen1);
373             wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
374             return FALSE;
375         }
376
377         // Look at the second file, if any
378         if (parser.GetParamCount() > 1)
379         {
380             if (ext2 == "ecc" || ext2 == "ECC")
381             {
382                 if (wxFileExists(filenameToOpen2))
383                 {
384                     if (gotSavefile)
385                     {
386                         wxString msg;
387                         msg.Printf("%s is a second save file -- please supply only one.", (const wxChar*) filenameToOpen2);
388                         wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
389                         return FALSE;
390                     }
391                     
392                     gotSavefile = TRUE;
393                     saveFile = filenameToOpen2;
394                 }
395                 else
396                 {
397                     wxString msg;
398                     msg.Printf("%s is not a valid file.", (const wxChar*) filenameToOpen2);
399                     wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
400                     return FALSE;
401                 }
402             }
403             else if (!gotSavefile && wxDirExists(filenameToOpen2) && FindSaveFileInDir(filenameToOpen2, tmpSaveFile))
404             {
405                 saveFile = tmpSaveFile;
406                 gotSavefile = TRUE;
407             }
408             else if ((name2 == wxT("ecos") && ext2 == wxT("db") && wxFileExists(filenameToOpen2)) || wxDirExists(filenameToOpen2))
409             {
410                 if (gotRepository)
411                 {
412                     wxString msg;
413                     msg.Printf("%s is a second repository -- please supply only one.", (const wxChar*) filenameToOpen2);
414                     wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
415                     return FALSE;
416                 }           
417                 
418                 // It's a repository (we hope).
419                 if (name1 == wxT("ecos") && ext1 == wxT("db"))
420                 {
421                     // Go two steps up
422                     filenameToOpen2 = wxPathOnly(filenameToOpen2);
423                     filenameToOpen2 = wxPathOnly(filenameToOpen2);
424                 }
425                 else
426                 {
427                     // If it's the packages directory, we need to strip off
428                     // a directory
429                     wxString eccPath(filenameToOpen2 + wxString(wxFILE_SEP_PATH) + wxT("ecc"));
430                     
431                     // Don't strip off ecc if it's the CVS repository (with ecc below it)
432                     if (name2 == wxT("packages") || (name2 == wxT("ecc") && !wxDirExists(eccPath)))
433                         filenameToOpen2 = wxPathOnly(filenameToOpen2);
434                 }
435                 
436                 repositoryDir = filenameToOpen2;
437                 gotRepository = TRUE;
438             }
439             else
440             {
441                 wxString msg;
442                 msg.Printf("%s is neither a project file nor a valid repository.", (const wxChar*) filenameToOpen2);
443                 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
444                 return FALSE;
445             }
446         }
447         
448         // Now we have looked at the two files and decided what they are; let's
449         // act on it.
450
451         if (gotRepository)
452         {
453             GetSettings().m_strRepository = repositoryDir;
454         }
455
456         if (!gotSavefile)
457         {
458             // See if there's a save file in the current dir
459             if (FindSaveFileInDir(currentDir, saveFile))
460                 gotSavefile = TRUE;
461         }
462
463         if (gotSavefile)
464         {
465             // The repository will be loaded from m_strRepository, possibly set above.
466             m_docManager->CreateDocument(saveFile, wxDOC_SILENT);
467         }
468         else
469         {
470             // Create a new file
471             m_docManager->CreateDocument(wxString(""), wxDOC_NEW);
472         }
473
474         if (compileHelpOnly)
475         {
476             if (!gotRepository)
477             {
478                 wxString msg;
479                 msg.Printf(wxT("Please specify a repository when using the --compile-help option."));
480                 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
481                 return FALSE;
482             }
483             ecConfigToolDoc* doc = wxGetApp().GetConfigToolDoc();
484             if (doc)
485             {
486                 if (!doc->RebuildHelpIndex(TRUE))
487                 {
488                     wxString msg;
489                     msg.Printf(wxT("Sorry, there was a problem compiling the help index."));
490                     wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
491                     return FALSE;                   
492                 }
493             }
494             else
495             {
496                 wxString msg;
497                 msg.Printf(wxT("Sorry, there was no current document when compiling the help index."));
498                 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
499                 return FALSE;                   
500             }
501
502             // Return FALSE in order to quit the application
503             return FALSE;
504         }
505     }
506     else
507     {
508         m_docManager->CreateDocument(wxString(""), wxDOC_NEW);
509     }
510
511     return TRUE;
512 }
513
514 // Load resources from disk
515 bool ecApp::LoadResources()
516 {
517     wxFileSystem::AddHandler(new wxMemoryFSHandler);
518
519 //    LoadBitmapResource(m_splashScreenBitmap, wxT("splash16.png"), wxBITMAP_TYPE_PNG, FALSE);
520
521 //    wxBitmap bitmap1, bitmap2, bitmap3;
522 //    LoadBitmapResource(bitmap1, wxT("ecoslogo.png"), wxBITMAP_TYPE_PNG, TRUE);
523 //    LoadBitmapResource(bitmap2, wxT("ecoslogosmall.png"), wxBITMAP_TYPE_PNG, TRUE);
524 //    LoadBitmapResource(bitmap3, wxT("rhlogo.png"), wxBITMAP_TYPE_PNG, TRUE);
525
526 //    wxString aboutText;
527 //    LoadTextResource(aboutText, wxT("about.htm"), TRUE);
528
529 //    VersionStampSplashScreen();
530
531     return TRUE;
532 }
533
534 // Load resources from zip resource file or disk
535 bool ecApp::LoadBitmapResource(wxBitmap& bitmap, const wxString& filename, int bitmapType, bool addToMemoryFS)
536 {
537     wxString archive(GetFullAppPath(wxT("configtool.bin")));
538
539 #if wxUSE_STREAMS && wxUSE_ZIPSTREAM && wxUSE_ZLIB
540     wxFSFile* file = m_fileSystem->OpenFile(archive + wxString(wxT("#zip:")) + filename);
541     if (file)
542     {
543         wxInputStream* stream = file->GetStream();
544         
545         wxImage image(* stream, bitmapType);
546         bitmap = image.ConvertToBitmap();
547         
548         delete file;
549     }
550 #endif
551
552 #ifdef __WXMSW__
553     if (!bitmap.Ok())
554         bitmap.LoadFile(filename, wxBITMAP_TYPE_BMP_RESOURCE);
555 #endif
556
557     if (!bitmap.Ok() && wxFileExists(GetFullAppPath(filename)))
558         bitmap.LoadFile(GetFullAppPath(filename), bitmapType);
559
560
561     if (bitmap.Ok() && addToMemoryFS)
562         wxMemoryFSHandler::AddFile(filename, bitmap, bitmapType);
563
564     return bitmap.Ok();
565 }
566
567 // Load resources from zip resource file or disk
568 bool ecApp::LoadTextResource(wxString& text, const wxString& filename, bool addToMemoryFS)
569 {
570     wxString archive(GetFullAppPath(wxT("configtool.bin")));
571
572     bool success = FALSE;
573
574 #if wxUSE_STREAMS && wxUSE_ZIPSTREAM && wxUSE_ZLIB
575     wxFSFile* file = m_fileSystem->OpenFile(archive + wxString(wxT("#zip:")) + filename);
576     if (file)
577     {
578         wxInputStream* stream = file->GetStream();
579
580         char* buf = text.GetWriteBuf(stream->GetSize() + 1);
581         stream->Read((void*) buf, stream->GetSize());
582         buf[stream->GetSize()] = 0;
583         text.UngetWriteBuf();
584
585         success = TRUE;
586         
587         delete file;
588     }
589 #endif
590
591     if (!success && wxFileExists(GetFullAppPath(filename)))
592     {
593         wxFileInputStream str(GetFullAppPath(filename));
594
595         char* buf = text.GetWriteBuf(str.GetSize() + 1);
596         str.Read((void*) buf, str.GetSize());
597         buf[str.GetSize()] = 0;
598         text.UngetWriteBuf();
599
600         success = TRUE;
601     }
602
603     if (success && addToMemoryFS)
604         wxMemoryFSHandler::AddFile(filename, text);
605
606     return success;
607 }
608
609 // Get a text resource from the memory filesystem
610 bool ecApp::GetMemoryTextResource(const wxString& filename, wxString& text)
611 {
612     wxString s(wxString(wxT("memory:")) + filename);
613     wxFSFile* file = wxGetApp().GetFileSystem()->OpenFile(s);
614     if (file)
615     {
616         wxInputStream* stream = file->GetStream();
617
618         char* buf = text.GetWriteBuf(stream->GetSize() + 1);
619         stream->Read((void*) buf, stream->GetSize());
620         buf[stream->GetSize()] = 0;
621         text.UngetWriteBuf();
622
623         delete file;
624         return TRUE;
625     }
626     else
627         return FALSE;
628 }
629
630 // Version-stamp the splash screen
631 bool ecApp::VersionStampSplashScreen()
632 {
633     if (m_splashScreenBitmap.Ok())
634     {
635         wxMemoryDC dc;
636         dc.SelectObject(m_splashScreenBitmap);
637
638         wxColour textColour(19, 49, 4);
639         dc.SetTextForeground(textColour);
640         dc.SetBackgroundMode(wxTRANSPARENT);
641         dc.SetFont(wxFont(11, wxSWISS, wxNORMAL, wxBOLD, FALSE));
642
643         // Bottom left of area to start drawing at
644
645         wxString verString;
646         verString.Printf("%.2f", ecCONFIGURATION_TOOL_VERSION);
647
648         int x = 339; int y = 231;
649 #ifdef __WXMSW__
650         y += 5; // For some reason
651 #endif
652         int w, h;
653         dc.GetTextExtent(verString, & w, & h);
654         dc.DrawText(verString, x, y - h);
655
656         dc.SelectObject(wxNullBitmap);
657
658         return TRUE;
659     }
660     else
661         return FALSE;
662 }
663
664 // Initialize window settings object
665 bool ecApp::InitializeWindowSettings(bool beforeWindowConstruction)
666 {
667     wxWindowSettings& settings = GetSettings().m_windowSettings;
668     ecMainFrame* frame = GetMainFrame();
669
670     if (beforeWindowConstruction)
671     {
672         settings.Add(wxT("Configuration"));       
673         settings.Add(wxT("Short Description"));
674         settings.Add(wxT("Output"));
675         settings.Add(wxT("Properties"));
676         settings.Add(wxT("Conflicts"));
677     }
678     else
679     {
680         wxArrayPtrVoid arr;
681         arr.Add(frame->GetTreeCtrl());
682         arr.Add(frame->GetValueWindow());
683         settings.SetWindows(wxT("Configuration"), arr);
684
685         settings.SetWindow(wxT("Short Description"), frame->GetShortDescriptionWindow());
686         settings.SetWindow(wxT("Output"), frame->GetOutputWindow());
687         settings.SetWindow(wxT("Properties"), frame->GetPropertyListWindow());
688         settings.SetWindow(wxT("Conflicts"), frame->GetConflictsWindow());
689     }
690
691     return TRUE;
692 }
693
694
695 bool ecApp::InitializeHelpController()
696 {
697     if (m_helpController)
698         delete m_helpController;
699     m_helpController = new wxHelpController;
700
701     if (!m_helpController->Initialize(GetHelpFile()))
702     {
703         // TODO
704         return FALSE;
705     }
706     else
707     {
708         // Tell the help controller where the repository documentation is.
709         // For now, just keep this to myself since it uses hacks to wxWin
710         ecConfigToolDoc* doc = GetConfigToolDoc();
711
712         // No longer using relative paths
713 #if 0
714         if (doc)
715         {
716             wxString htmlDir = wxString(doc->GetRepository()) + wxString(wxT("/doc/html"));
717             if (!wxDirExists(htmlDir))
718                 htmlDir = wxString(doc->GetRepository()) + wxString(wxT("/doc"));
719
720             htmlDir += wxString(wxT("/"));
721
722             wxGetApp().GetHelpController().SetBookBasePath(htmlDir);
723         }
724 #endif
725         return TRUE;
726     }
727 }
728
729 // Check if there is a (unique) .ecc file in dir
730 bool ecApp::FindSaveFileInDir(const wxString& dir, wxString& saveFile)
731 {
732     wxDir fileFind;
733     
734     if (!fileFind.Open(dir))
735         return FALSE;
736     
737     wxString wildcard = wxT(".ecc");   
738     wxString filename;
739
740     bool found = fileFind.GetFirst (& filename, wildcard);
741     if (found)
742     {
743         // Fail if there was more than one matching file.
744         wxString filename2;
745         if (fileFind.GetNext (& filename2))
746             return FALSE;
747         else
748         {
749             saveFile = dir + wxString(wxFILE_SEP_PATH) + filename;
750             return TRUE;
751         }
752     }
753     return FALSE;
754 }
755
756 int ecApp::OnExit(void)
757 {
758 /*
759     if (m_helpController)
760     {
761         delete m_helpController;
762         m_helpController = NULL;
763     }
764 */
765
766     if (m_splashScreen)
767     {
768         m_splashScreen->Destroy();
769         m_splashScreen = NULL;
770     }
771
772     m_settings.SaveConfig();
773
774     {
775         wxConfig config(wxGetApp().GetSettings().GetConfigAppName());
776         if (config.HasGroup(wxT("FileHistory")))
777             config.DeleteGroup(wxT("FileHistory"));
778         config.SetPath(wxT("FileHistory/"));
779         m_docManager->FileHistorySave(config);
780     }
781
782     delete m_docManager;
783
784     return 0;
785 }
786
787 // Prepend the current program directory to the name
788 wxString ecApp::GetFullAppPath(const wxString& filename) const
789 {
790     wxString path(m_appDir);
791     if (path.Last() != '\\' && path.Last() != '/' && filename[0] != '\\' && filename[0] != '/')
792 #ifdef __WXGTK__
793         path += '/';
794 #else
795         path += '\\';
796 #endif
797     path += filename;
798     
799     return path;
800 }
801
802 // Are we running in 32K colours or more?
803 bool ecApp::GetHiColour() const
804 {
805     static bool hiColour = (wxDisplayDepth() >= 16) ;
806     return hiColour;
807 }
808
809 // General handler for 'What's this?'
810 void ecApp::OnWhatsThis(wxCommandEvent& event)
811 {
812     wxObject* obj = event.GetEventObject();
813     wxWindow* win = NULL;
814
815     if (obj->IsKindOf(CLASSINFO(wxMenu)))
816     {
817         win = ((wxMenu*) obj)->GetInvokingWindow();
818     }
819     else if (obj->IsKindOf(CLASSINFO(wxWindow)))
820     {
821         win = (wxWindow*) obj;
822     }
823
824     wxWindow* subjectOfHelp = win;
825     bool eventProcessed = FALSE;
826     wxPoint pt = wxGetMousePosition();
827
828     while (subjectOfHelp && !eventProcessed)
829     {
830         wxHelpEvent helpEvent(wxEVT_HELP, subjectOfHelp->GetId(), pt) ;
831         helpEvent.SetEventObject(this);
832         eventProcessed = win->GetEventHandler()->ProcessEvent(helpEvent);
833         
834         // Go up the window hierarchy until the event is handled (or not).
835         // I.e. keep submitting ancestor windows until one is recognised
836         // by the app code that processes the ids and displays help.
837         subjectOfHelp = subjectOfHelp->GetParent();
838     }
839     // wxGetApp().GetHelpController().DisplayTextPopup(GetHelpText(), wxGetMousePosition());
840 }
841
842 // Log to output window
843 void ecApp::Log(const wxString& msg)
844 {
845     ecMainFrame* frame = (ecMainFrame*) GetTopWindow();
846     if (frame)
847     {
848         frame->GetOutputWindow()->AppendText(msg /* + wxT("\n") */ );
849         if ((msg == wxEmptyString) || (msg.Last() != wxT('\n')))
850             frame->GetOutputWindow()->AppendText(wxT("\n"));
851
852         frame->GetOutputWindow()->ShowPosition(frame->GetOutputWindow()->GetLastPosition());
853     }
854 }
855
856 void ecApp::SetStatusText(const wxString& text, bool clearFailingRulesPane)
857 {
858     ecMainFrame* mainFrame = GetMainFrame();
859     if(mainFrame)
860     {
861         mainFrame->GetStatusBar()->SetStatusText(text, ecStatusPane);
862         if (clearFailingRulesPane)
863             mainFrame->GetStatusBar()->SetStatusText(wxT(""), ecFailRulePane);
864 #ifdef __WXMSW__
865         ::UpdateWindow((HWND) mainFrame->GetHWND());
866         //wxYield();
867 #endif
868     }
869 }
870
871 // Config tree control
872 ecConfigTreeCtrl* ecApp::GetTreeCtrl() const
873 {
874     return GetMainFrame()->GetTreeCtrl();
875 }
876
877 // MLT window
878 ecMemoryLayoutWindow* ecApp::GetMLTWindow() const
879 {
880     return GetMainFrame()->GetMemoryLayoutWindow();
881 }
882
883 // Get active document
884 ecConfigToolDoc* ecApp::GetConfigToolDoc() const
885 {
886     if (m_currentDoc)
887         return m_currentDoc;
888
889     if (!m_docManager)
890         return NULL;
891
892     return wxDynamicCast(m_docManager->GetCurrentDocument(), ecConfigToolDoc);
893 }
894
895 bool ecApp::Launch(const wxString & strFileName,const wxString &strViewer)
896 {
897     bool ok = FALSE;
898     wxString cmd;
899
900     if (!strViewer.IsEmpty())
901     {
902         cmd = strViewer + wxString(wxT(" ")) + strFileName ;
903     }
904     else
905     {
906         wxString path, filename, ext;
907         wxSplitPath(strFileName, & path, & filename, & ext);
908         
909         wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
910         if ( !ft )
911         {
912             wxLogError(_T("Impossible to determine the file type for extension '%s'"),
913                 ext.c_str());
914             return FALSE;
915         }
916
917         bool ok = ft->GetOpenCommand(&cmd,
918             wxFileType::MessageParameters(strFileName, _T("")));
919         delete ft;
920         
921         if (!ok)
922         {
923             // TODO: some kind of configuration dialog here.
924             wxMessageBox(_("Could not determine the command for opening this file."),
925                 wxGetApp().GetSettings().GetAppName(), wxOK|wxICON_EXCLAMATION);
926             return FALSE;
927         }
928     }        
929
930     ok = (wxExecute(cmd, FALSE) != 0);
931     
932     return ok;
933
934 #if 0    
935     bool rc=false;
936     
937     if(!strViewer.IsEmpty())//use custom editor
938     {
939         CString strCmdline(strViewer);
940         
941         TCHAR *pszCmdLine=strCmdline.GetBuffer(strCmdline.GetLength());
942         GetShortPathName(pszCmdLine,pszCmdLine,strCmdline.GetLength());
943         strCmdline.ReleaseBuffer();
944         
945         strCmdline+=_TCHAR(' ');
946         strCmdline+=strFileName;
947         PROCESS_INFORMATION pi;
948         STARTUPINFO si;
949         
950         si.cb = sizeof(STARTUPINFO); 
951         si.lpReserved = NULL; 
952         si.lpReserved2 = NULL; 
953         si.cbReserved2 = 0; 
954         si.lpDesktop = NULL; 
955         si.dwFlags = 0; 
956         si.lpTitle=NULL;
957         
958         if(CreateProcess(
959             NULL, // app name
960             //strCmdline.GetBuffer(strCmdline.GetLength()),    // command line
961             strCmdline.GetBuffer(strCmdline.GetLength()),    // command line
962             NULL, // process security
963             NULL, // thread security
964             TRUE, // inherit handles
965             0,
966             NULL, // environment
967             NULL, // current dir
968             &si, // startup info
969             &pi)){
970             CloseHandle(pi.hProcess);
971             CloseHandle(pi.hThread);
972             rc=true;
973         } else {
974             CUtils::MessageBoxF(_T("Failed to invoke %s.\n"),strCmdline);
975         }
976         strCmdline.ReleaseBuffer();
977     } else {// Use association
978         TCHAR szExe[MAX_PATH];
979         HINSTANCE h=FindExecutable(strFileName,_T("."),szExe);
980         if(int(h)<=32){
981             CString str;
982             switch(int(h)){
983             case 0:  str=_T("The system is out of memory or resources.");break;
984             case 31: str=_T("There is no association for the specified file type.");break;
985             case ERROR_FILE_NOT_FOUND: str=_T("The specified file was not found.");break;
986             case ERROR_PATH_NOT_FOUND: str=_T("The specified path was not found.");break;
987             case ERROR_BAD_FORMAT:     str=_T("The .EXE file is invalid (non-Win32 .EXE or error in .EXE image).");break;
988             default: break;
989             }
990             CUtils::MessageBoxF(_T("Failed to open document %s.\r\n%s"),strFileName,str);
991         } else {
992             
993             SHELLEXECUTEINFO sei = {sizeof(sei), 0, AfxGetMainWnd()->GetSafeHwnd(), _T("open"),
994                 strFileName, NULL, NULL, SW_SHOWNORMAL, AfxGetInstanceHandle( )};
995             
996             sei.hInstApp=0;
997             HINSTANCE hInst=ShellExecute(AfxGetMainWnd()->GetSafeHwnd(),_T("open"), strFileName, NULL, _T("."), 0)/*ShellExecuteEx(&sei)*/;
998             if(int(hInst)<=32/*sei.hInstApp==0*/)
999             {
1000                 CString str;
1001                 switch(int(hInst))
1002                 {
1003                 case 0 : str=_T("The operating system is out of memory or resources. ");break;
1004                 case ERROR_FILE_NOT_FOUND : str=_T("The specified file was not found. ");break;
1005                 case ERROR_PATH_NOT_FOUND : str=_T("The specified path was not found. ");break;
1006                 case ERROR_BAD_FORMAT : str=_T("The .EXE file is invalid (non-Win32 .EXE or error in .EXE image). ");break;
1007                 case SE_ERR_ACCESSDENIED : str=_T("The operating system denied access to the specified file. ");break;
1008                 case SE_ERR_ASSOCINCOMPLETE : str=_T("The filename association is incomplete or invalid. ");break;
1009                 case SE_ERR_DDEBUSY : str=_T("The DDE transaction could not be completed because other DDE transactions were being processed. ");break;
1010                 case SE_ERR_DDEFAIL : str=_T("The DDE transaction failed. ");break;
1011                 case SE_ERR_DDETIMEOUT : str=_T("The DDE transaction could not be completed because the request timed out. ");break;
1012                 case SE_ERR_DLLNOTFOUND : str=_T("The specified dynamic-link library was not found. ");break;
1013                     //case SE_ERR_FNF : str=_T("The specified file was not found. ");break;
1014                 case SE_ERR_NOASSOC : str=_T("There is no application associated with the given filename extension. ");break;
1015                 case SE_ERR_OOM : str=_T("There was not enough memory to complete the operation. ");break;
1016                     //case SE_ERR_PNF : str=_T("The specified path was not found. ");break;
1017                 case SE_ERR_SHARE : str=_T("A sharing violation occurred. ");break;
1018                 default: str=_T("An unexpected error occurred");break;
1019                 }
1020                 CUtils::MessageBoxF(_T("Failed to open document %s using %s.\r\n%s"),strFileName,szExe,str);
1021             } else {
1022                 rc=true;
1023             }
1024         }
1025     }
1026     return rc;
1027 #endif
1028 }
1029
1030 bool ecApp::PrepareEnvironment(bool bWithBuildTools, wxString* cmdLine)
1031 {
1032 #ifdef __WXMSW__
1033     // Under Windows we can set variables.
1034     ecConfigToolDoc *pDoc = GetConfigToolDoc();
1035     
1036     wxSetEnv(wxT("PATH"), m_strOriginalPath);
1037     
1038     const wxString strPrefix(pDoc->GetCurrentTargetPrefix());
1039     ecFileName strBinDir;
1040     bool rc = FALSE;
1041
1042     rc=(! bWithBuildTools) || GetSettings().m_arstrBinDirs.Find(strPrefix, strBinDir);
1043     if(!rc)
1044     {
1045         // Use fallback of previously-entered build tools directory, if available
1046         if (!GetSettings().m_buildToolsDir.IsEmpty())
1047         {
1048             strBinDir = GetSettings().m_buildToolsDir ;
1049             rc = TRUE;
1050         }
1051         else
1052         {
1053             wxCommandEvent event;
1054             GetMainFrame()->OnBuildToolsPath(event);
1055             rc = GetSettings().m_arstrBinDirs.Find(strPrefix, strBinDir);
1056         }
1057     }
1058     
1059     if (rc)
1060     {
1061         ecFileName strUserBinDir(GetSettings().m_userToolsDir);
1062         if(strUserBinDir.IsEmpty())
1063         {
1064             if ( 1 == GetSettings().m_userToolPaths.GetCount() )
1065             {
1066                 GetSettings().m_userToolsDir = GetSettings().m_userToolPaths[0];
1067             } else
1068             {
1069                 wxCommandEvent event;
1070                 GetMainFrame()->OnUserToolsPath(event);
1071             }
1072             strUserBinDir = GetSettings().m_userToolsDir;
1073         }
1074         if ( !strUserBinDir.IsEmpty() )
1075         {
1076             // calculate the directory of the host tools from this application's module name
1077             ecFileName strHostToolsBinDir(this->argv[0]);
1078             strHostToolsBinDir = strHostToolsBinDir.Head ();
1079             
1080             // tools directories are in the order host-tools, user-tools, comp-tools, install/bin (if present), contrib-tools (if present) on the path
1081             const ecFileName strContribBinDir(strUserBinDir, wxT("..\\contrib\\bin"));
1082             ecFileName strUsrBinDir(strUserBinDir, wxT("..\\usr\\bin"));
1083             const ecFileName strInstallBinDir(pDoc->GetInstallTree (), wxT("bin"));
1084
1085             // In case strUserBinDir is e.g. c:\program files\red hat\cygwin-00r1\usertools\h-i686-pc-cygwin\bin
1086             if (!strUsrBinDir.IsDir ())
1087                 strUsrBinDir = ecFileName(strUserBinDir + _T("..\\..\\..\\H-i686-pc-cygwin\\bin"));
1088
1089             if (
1090                 (strUsrBinDir.IsDir ()     && ! ecUtils::AddToPath (strUsrBinDir)) || 
1091                 (strContribBinDir.IsDir () && ! ecUtils::AddToPath (strContribBinDir)) || 
1092                 (strInstallBinDir.IsDir () && ! ecUtils::AddToPath (strInstallBinDir)) || 
1093                 (bWithBuildTools && ! ecUtils::AddToPath (strBinDir)) || 
1094                 ! ecUtils::AddToPath (strUserBinDir) || 
1095                 ! ecUtils::AddToPath (strHostToolsBinDir))
1096             {
1097                 wxString msg;
1098                 msg.Printf(wxT("Failed to set PATH environment variable"));
1099                 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
1100                 rc = FALSE;
1101             } else
1102             {
1103                 if(!wxSetEnv(_T("MAKE_MODE"),_T("unix")))
1104                 {
1105                     wxString msg;
1106                     msg.Printf(wxT("Failed to set MAKE_MODE environment variable"));
1107                     wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
1108                     rc = FALSE;
1109                 } else
1110                 {
1111                     // Remove from the environment
1112                     wxUnsetEnv(wxT("GDBTK_LIBRARY"));
1113                     wxUnsetEnv(wxT("GCC_EXEC_PREFIX"));
1114
1115                     // Useful for ecosconfig
1116                     wxSetEnv(wxT("ECOS_REPOSITORY"), pDoc->GetPackagesDir());
1117
1118                     // Mount /ecos-x so we can access these in text mode
1119                     if (! pDoc->GetBuildTree().IsEmpty() && wxIsalpha(pDoc->GetBuildTree()[0]))
1120                         CygMount(pDoc->GetBuildTree()[0]);
1121                     if (! pDoc->GetInstallTree().IsEmpty() && wxIsalpha(pDoc->GetInstallTree()[0]))
1122                         CygMount(pDoc->GetInstallTree()[0]);
1123                     if (! pDoc->GetRepository().IsEmpty() && wxIsalpha(pDoc->GetRepository()[0]))
1124                         CygMount(pDoc->GetRepository()[0]);
1125                 }
1126             }
1127         }
1128     }
1129     return rc;
1130 #else
1131     wxASSERT ( cmdLine != NULL );
1132
1133     (* cmdLine) = wxEmptyString;
1134
1135     // Under Unix we need to build up a command line to set variables and invoke make
1136     ecConfigToolDoc *pDoc = GetConfigToolDoc();
1137     
1138     const wxString strPrefix(pDoc->GetCurrentTargetPrefix());
1139     ecFileName strBinDir;
1140     bool rc = FALSE;
1141
1142     rc=(! bWithBuildTools) || GetSettings().m_arstrBinDirs.Find(strPrefix, strBinDir);
1143     if(!rc)
1144     {
1145         // Use fallback of previously-entered build tools directory, if available
1146         if (!GetSettings().m_buildToolsDir.IsEmpty())
1147         {
1148             strBinDir = GetSettings().m_buildToolsDir ;
1149             rc = TRUE;
1150         }
1151         else
1152         {
1153             wxCommandEvent event;
1154             GetMainFrame()->OnBuildToolsPath(event);
1155             rc = GetSettings().m_arstrBinDirs.Find(strPrefix, strBinDir);
1156         }
1157     }
1158     
1159     if (rc)
1160     {
1161         if (!strBinDir.IsEmpty())
1162         {
1163             (* cmdLine) += wxString(wxT("export PATH=")) + wxString(strBinDir) + wxT(":$PATH; ");
1164             
1165             // Also set the path
1166             wxString oldPath(wxGetenv(wxT("PATH")));
1167             wxString path(strBinDir);
1168             if (!oldPath.IsEmpty())
1169             {
1170                 path += wxT(":");
1171                 path += oldPath;
1172             }
1173             wxSetEnv(wxT("PATH"), path);
1174         }
1175         (* cmdLine) += wxString(wxT("unset GDBTK_LIBRARY; ")) ;
1176         wxUnsetEnv(wxT("GDBTK_LIBRARY"));
1177         
1178         (* cmdLine) += wxString(wxT("unset GCC_EXEC_PREFIX; ")) ;
1179         wxUnsetEnv(wxT("GCC_EXEC_PREFIX"));
1180         
1181         (* cmdLine) += wxString(wxT("export ECOS_REPOSITORY=")) + wxString(pDoc->GetPackagesDir()) + wxT("; ");
1182         wxSetEnv(wxT("ECOS_REPOSITORY"), pDoc->GetPackagesDir());
1183         
1184 #if 0
1185         ecFileName strUserBinDir(GetSettings().m_userToolsDir);
1186         if(strUserBinDir.IsEmpty())
1187         {
1188             if ( 1 == GetSettings().m_userToolPaths.GetCount() )
1189             {
1190                 GetSettings().m_userToolsDir = GetSettings().m_userToolPaths[0];
1191             } else
1192             {
1193                 wxCommandEvent event;
1194                 GetMainFrame()->OnUserToolsPath(event);
1195             }
1196             strUserBinDir = GetSettings().m_userToolsDir;
1197         }
1198         if ( !strUserBinDir.IsEmpty() )
1199         {
1200             // calculate the directory of the host tools from this application's module name
1201             ecFileName strHostToolsBinDir(this->argv[0]);
1202             strHostToolsBinDir = strHostToolsBinDir.Head ();
1203             
1204             // tools directories are in the order host-tools, user-tools, comp-tools, install/bin (if present), contrib-tools (if present) on the path
1205             
1206             // TODO: is this right? Assuming that the user tools are already in the user's path.
1207             // const ecFileName strContribBinDir(strUserBinDir, wxT("..\\contrib\\bin"));
1208             // const ecFileName strUsrBinDir(strUserBinDir, wxT("..\\usr\\bin"));
1209             const ecFileName strInstallBinDir(pDoc->GetInstallTree (), wxT("bin"));
1210             
1211             (* cmdLine) += wxString(wxT("export PATH=")) + wxString(strInstallBinDir) + wxT(":$PATH; ");
1212             (* cmdLine) += wxString(wxT("unset GDBTK_LIBRARY; ")) ;
1213             (* cmdLine) += wxString(wxT("unset GCC_EXEC_PREFIX; ")) ;
1214             (* cmdLine) += wxString(wxT("export ECOS_REPOSITORY=")) + wxString(pDoc->GetPackagesDir()) + wxT("; ");
1215         }
1216 #endif
1217     }
1218     return rc;
1219 #endif
1220 }
1221
1222 void ecApp::CygMount(wxChar c)
1223 {
1224     // May not be alpha if it's e.g. a UNC network path
1225     if (!wxIsalpha(c))
1226         return;
1227     
1228     c = wxTolower(c);
1229     
1230     if(!sm_arMounted[c-_TCHAR('a')])
1231     {
1232         sm_arMounted[c-wxChar('a')]=true;
1233         wxString strCmd;
1234         String strOutput;
1235         
1236         strCmd.Printf(wxT("mount %c: /ecos-%c"),c,c);
1237         CSubprocess sub;
1238         sub.Run(strOutput,strCmd);
1239     }
1240
1241
1242     // Doing it with wxExecute results in a flashing DOS box unfortunately
1243 #if 0
1244     wxASSERT(wxIsalpha(c));
1245     c = wxTolower(c);
1246     if(!sm_arMounted[c-wxChar('a')])
1247     {
1248         sm_arMounted[c-wxChar('a')] = TRUE;
1249         wxString strCmd;
1250         
1251         strCmd.Printf(wxT("mount.exe %c: /%c"),c,c);
1252
1253         wxExecute(strCmd, TRUE);
1254     }
1255 #endif
1256 }
1257
1258 // Fiddling directly with the registry DOESN'T WORK because Cygwin mount tables
1259 // get out of synch with the registry
1260 void ecApp::CygMountText(wxChar c)
1261 {
1262     wxASSERT(wxIsalpha(c));
1263     c = wxTolower(c);
1264 //    if(!sm_arMounted[c-wxChar('a')])
1265     {
1266 //        sm_arMounted[c-wxChar('a')] = TRUE;
1267
1268 #if 0        
1269         wxString strCmd;
1270         
1271         strCmd.Printf(wxT("mount.exe %c: /ecos-%c"),c,c);
1272
1273         wxExecute(strCmd, TRUE);
1274 #else
1275         wxString key, value;
1276         key.Printf(wxT("/ecos-%c"), c);
1277         value.Printf(wxT("%c:"), c);
1278
1279         // Mount by fiddling with registry instead, so we don't see ugly flashing windows
1280 #ifdef __WXMSW__
1281         HKEY hKey = 0;
1282         if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Cygnus Solutions\\Cygwin\\mounts v2",
1283             0, KEY_READ, &hKey))
1284         {
1285             DWORD disposition;
1286             HKEY hSubKey = 0;
1287
1288             if (ERROR_SUCCESS == RegCreateKeyEx(hKey, key, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
1289                 NULL, & hSubKey, & disposition))
1290             {
1291                 RegSetValueEx(hSubKey, "native", 0, REG_SZ, (unsigned char*) (const wxChar*) value, value.Length() + 1);
1292                 RegCloseKey(hSubKey);
1293             }
1294             
1295             RegCloseKey(hKey);
1296         }
1297 #endif
1298
1299 #endif
1300     }
1301 }
1302
1303 void ecApp::Build(const wxString &strWhat /*=wxT("")*/ )
1304 {
1305     if (m_pipedProcess)
1306         return;
1307
1308     ecConfigToolDoc* pDoc = GetConfigToolDoc();
1309     if (!pDoc)
1310         return;
1311
1312     if (!wxGetApp().GetMainFrame()->GetOutputWindow()->IsShown())
1313     {
1314         wxGetApp().GetMainFrame()->ToggleWindow(ecID_TOGGLE_OUTPUT);
1315     }
1316     if (!pDoc->GetDocumentSaved())
1317     {
1318         pDoc->SaveAs();
1319     }
1320 /*
1321     if (pDoc->IsModified() && !wxDirExists(pDoc->GetBuildTree()))
1322     {
1323         pDoc->SaveAs();
1324     }
1325 */
1326 //    if ( !(pDoc->IsModified() || !wxDirExists(pDoc->GetBuildTree())) ) // verify the save worked
1327     if ( pDoc->GetDocumentSaved() )
1328     {
1329         //wxString strCmd (wxT("c:\\bin\\testmake.bat"));
1330         wxString strCmd (wxT("make"));
1331         if(!strWhat.IsEmpty())
1332         {
1333             strCmd += wxT(' ');
1334             strCmd += strWhat;
1335         }
1336
1337         if(!GetSettings().m_strMakeOptions.IsEmpty())
1338         {
1339             strCmd += wxT(' ');
1340             strCmd += GetSettings().m_strMakeOptions;
1341         }
1342         strCmd += wxT(" --directory ");
1343
1344         // Quoting the name may not mix with the 'sh' command on Unix, so only do it
1345         // under Windows where it's more likely there will be spaces needing quoting.
1346 #ifdef __WXMSW__
1347         wxString buildDir(pDoc->GetBuildTree());
1348
1349 #if ecUSE_ECOS_X_NOTATION
1350         std::string cPath = cygpath(std::string(pDoc->GetBuildTree()));
1351         buildDir = cPath.c_str();
1352 #endif
1353         strCmd += wxString(wxT("\"")) + buildDir + wxString(wxT("\""));
1354 #else
1355         strCmd += wxString(pDoc->GetBuildTree()) ;
1356 #endif
1357
1358         wxString variableSettings;
1359
1360         if (PrepareEnvironment(TRUE, & variableSettings))
1361         {
1362 #ifdef __WXMSW__
1363             // strCmd is all we need
1364 #else
1365             // strCmd has to invoke a shell with variables and make invocation
1366             strCmd = wxString(wxT("sh -c \"")) + variableSettings + strCmd + wxString(wxT("\""));
1367 #endif
1368             // Output the command so we know what we're doing
1369             Log(strCmd);
1370             Log(wxT("\n"));
1371
1372             // No: pass --directory
1373             // wxSetWorkingDirectory(pDoc->GetBuildTree());
1374
1375             m_pipedProcess = new ecPipedProcess;
1376             long pid = wxExecute(strCmd, FALSE, m_pipedProcess);
1377             if ( pid )
1378             {
1379                 m_pipedProcess->SetPid(pid);
1380                 // wxLogStatus(_T("Process %ld (%s) launched."), pid, cmd.c_str());
1381             }
1382             else
1383             {
1384                 wxLogError(_T("Execution of '%s' failed."), strCmd.c_str());
1385                 
1386                 delete m_pipedProcess;
1387                 m_pipedProcess  = NULL;
1388             }
1389         }
1390
1391 #if 0        
1392         if(PrepareEnvironment())
1393         {
1394             m_strBuildTarget=strWhat;
1395             SetThermometerMax(250); // This is just a guess.  The thread we are about to spawn will work out the correct answer
1396             m_nLogicalLines=0;
1397             UpdateThermometer(0);
1398             CloseHandle(CreateThread(NULL, 0, ThreadFunc, this, 0 ,&m_dwThreadId));
1399             CString strMsg;
1400             strMsg.Format(_T("Building %s"),strWhat);
1401             SetIdleMessage(strMsg);
1402             
1403             SetTimer(42,1000,0); // This timer checks for process completion
1404             SetCurrentDirectory(pDoc->BuildTree());
1405             m_sp.Run(SubprocessOutputFunc, this, strCmd, false);
1406             SetIdleMessage();
1407         }
1408 #endif
1409     }
1410 #if 0
1411     
1412     if(pDoc->IsModified()||pDoc->BuildTree().IsEmpty()){
1413         SendMessage (WM_COMMAND, ID_FILE_SAVE);
1414     }
1415     
1416     if(!(pDoc->IsModified()||pDoc->BuildTree().IsEmpty())){ // verify the save worked
1417         CString strCmd (_T("make"));
1418         if(!strWhat.IsEmpty()){
1419             strCmd+=_TCHAR(' ');
1420             strCmd+=strWhat;
1421         }
1422         if(!GetApp()->m_strMakeOptions.IsEmpty()){
1423             strCmd+=_TCHAR(' ');
1424             strCmd+=GetApp()->m_strMakeOptions;
1425         }
1426         
1427         if(PrepareEnvironment()){
1428             m_strBuildTarget=strWhat;
1429             SetThermometerMax(250); // This is just a guess.  The thread we are about to spawn will work out the correct answer
1430             m_nLogicalLines=0;
1431             UpdateThermometer(0);
1432             CloseHandle(CreateThread(NULL, 0, ThreadFunc, this, 0 ,&m_dwThreadId));
1433             CString strMsg;
1434             strMsg.Format(_T("Building %s"),strWhat);
1435             SetIdleMessage(strMsg);
1436             
1437             SetTimer(42,1000,0); // This timer checks for process completion
1438             SetCurrentDirectory(pDoc->BuildTree());
1439             m_sp.Run(SubprocessOutputFunc, this, strCmd, false);
1440             SetIdleMessage();
1441         }
1442     }
1443 #endif
1444 }
1445
1446 void ecApp::OnProcessTerminated(wxProcess* process)
1447 {
1448     m_pipedProcess = NULL;
1449 }
1450
1451 // ----------------------------------------------------------------------------
1452 // ecPipedProcess
1453 // ----------------------------------------------------------------------------
1454
1455 bool ecPipedProcess::HasInput()
1456 {
1457     bool hasInput = FALSE;
1458
1459     wxInputStream& is = *GetInputStream();
1460     if ( !is.Eof() )
1461     {
1462         wxTextInputStream tis(is);
1463
1464         // this assumes that the output is always line buffered
1465         wxString msg;
1466         msg << tis.ReadLine();
1467
1468         wxGetApp().Log(msg);
1469
1470         hasInput = TRUE;
1471     }
1472
1473     wxInputStream& es = *GetErrorStream();
1474     if ( !es.Eof() )
1475     {
1476         wxTextInputStream tis(es);
1477
1478         // this assumes that the output is always line buffered
1479         wxString msg;
1480         msg << tis.ReadLine();
1481
1482         wxGetApp().Log(msg);
1483
1484         hasInput = TRUE;
1485     }
1486
1487     return hasInput;
1488 }
1489
1490 void ecPipedProcess::OnTerminate(int pid, int status)
1491 {
1492     // show the rest of the output
1493     while ( HasInput() )
1494         ;
1495
1496     wxGetApp().OnProcessTerminated(this);
1497
1498     //wxLogStatus(m_parent, _T("Process %u ('%s') terminated with exit code %d."),
1499     //            pid, m_cmd.c_str(), status);
1500
1501     // we're not needed any more
1502     delete this;
1503 }
1504
1505 void ecPingTimer::Notify()
1506 {
1507     static bool s_inNotify = FALSE;
1508
1509     if (s_inNotify)
1510         return;
1511
1512     s_inNotify = TRUE;
1513
1514     // On Windows, simply having the timer going will ping the message queue
1515     // and cause idle processing to happen.
1516     // On Unix, this doesn't happen so we have to do the processing explicitly.
1517 #ifdef __WXMSW__
1518     // Nothing to do
1519 #else
1520     // Get some input
1521     if ( wxGetApp().m_pipedProcess )
1522         while (wxGetApp().m_pipedProcess->HasInput())
1523         {
1524             // Loop while there is still input
1525         }
1526 #endif
1527
1528     s_inNotify = FALSE;
1529 }
1530