unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / tools / src / tools / configtool / standalone / wxwin / admindlg.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 // admindlg.cpp :
27 //
28 //===========================================================================
29 //#####DESCRIPTIONBEGIN####
30 //
31 // Author(s):   julians,jld
32 // Contact(s):  julians
33 // Date:        2000/09/28
34 // Version:     $Id$
35 // Purpose:
36 // Description: Implementation file for ecAdminDialog
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 "admindlg.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 // For registry access functions in GetUserToolsPath
66 #ifdef __WXMSW__
67 #include <windows.h>
68 #include "wx/msw/winundef.h"
69 #endif
70
71 #include "wx/cshelp.h"
72 #include "wx/filedlg.h"
73 #include "wx/file.h"
74 #include "wx/filefn.h"
75 #include "wx/progdlg.h"
76
77 #include "configtool.h"
78 #include "admindlg.h"
79 #include "configtooldoc.h"
80 #include "licensedlg.h"
81 #include "ecutils.h"
82
83 #ifdef __WXGTK__
84 #include "bitmaps/package_open.xpm"
85 #include "bitmaps/package_version.xpm"
86 #endif
87
88 BEGIN_EVENT_TABLE(ecAdminDialog, ecDialog)
89     EVT_BUTTON(wxID_OK, ecAdminDialog::OnClose)
90     EVT_BUTTON(ecID_ADMIN_DIALOG_ADD, ecAdminDialog::OnAdd)
91     EVT_BUTTON(ecID_ADMIN_DIALOG_REMOVE, ecAdminDialog::OnRemove)
92     EVT_INIT_DIALOG(ecAdminDialog::OnInitDialog)
93 END_EVENT_TABLE()
94
95 // ----------------------------------------------------------------------------
96 // main frame
97 // ----------------------------------------------------------------------------
98
99 // Frame constructor
100 ecAdminDialog::ecAdminDialog(wxWindow* parent, const wxString& repository, const wxString& userTools):
101     m_imageList(16, 16, 1)
102 {
103     m_strRepository = repository;
104     m_strUserTools = userTools;
105         m_CdlPkgData = NULL;
106
107     SetExtraStyle(wxDIALOG_EX_CONTEXTHELP);
108
109     ecDialog::Create(parent, ecID_ADMIN_DIALOG, _("Administration"),
110         wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER);
111
112     CreateControls(this);
113
114     m_imageList.Add(wxICON(package_open));
115     m_imageList.Add(wxICON(package_version));
116     m_treeCtrl->SetImageList(& m_imageList);
117
118     Centre(wxBOTH);
119 }
120
121 ecAdminDialog::~ecAdminDialog()
122 {
123         ClearPackageTree ();
124
125         // free memory allocated to the CDL database
126
127         if (m_CdlPkgData)
128                 delete m_CdlPkgData;
129
130     m_treeCtrl->SetImageList(NULL);
131 }
132
133 void ecAdminDialog::OnInitDialog(wxInitDialogEvent& event)
134 {
135     // setup the path to the user tools (tar and gunzip)
136     
137     if ((! m_strUserTools.IsEmpty()) || FindUserToolsPath ()) // if the user tools can be located
138     {
139         wxString path;
140         wxGetEnv(wxT("PATH"), & path);
141         
142         // TODO: this may not work on all platforms
143         path = path + wxString(wxPATH_SEP) + m_strUserTools;
144         wxSetEnv(wxT("PATH"), path);
145     }
146     
147     // populate the package tree
148
149     if (!PopulatePackageTree (m_strRepository))
150     {
151         m_strRepository = wxT("");
152         // TODO
153         // OnPkgadminRepository (); // prompt the user for the repository location
154     }
155 }
156
157 void ecAdminDialog::CreateControls(wxWindow* parent)
158 {
159     m_treeCtrl = new wxTreeCtrl(parent, ecID_ADMIN_DIALOG_TREE,
160         wxDefaultPosition, wxSize(380, 290), wxTR_HAS_BUTTONS | wxSUNKEN_BORDER);
161
162     wxSizer *item0 = new wxBoxSizer( wxHORIZONTAL );
163
164     wxSizer *item1 = new wxBoxSizer( wxVERTICAL );
165
166     wxStaticText *item2 = new wxStaticText( parent, wxID_STATIC, _("&Installed packages:"), wxDefaultPosition, wxDefaultSize, 0 );
167     item1->Add( item2, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
168
169     wxWindow *item3 = parent->FindWindow( ecID_ADMIN_DIALOG_TREE );
170     wxASSERT( item3 );
171     item1->Add( item3, 1, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5 );
172
173     item0->Add( item1, 1, wxGROW|wxALIGN_CENTER_HORIZONTAL|wxALL, 5 );
174
175     wxSizer *item4 = new wxBoxSizer( wxVERTICAL );
176
177     wxButton *item5 = new wxButton( parent, ecID_ADMIN_DIALOG_ADD, _("&Add..."), wxDefaultPosition, wxDefaultSize, 0 );
178     item4->Add( item5, 0, wxALIGN_CENTRE|wxALL, 5 );
179
180     wxButton *item6 = new wxButton( parent, ecID_ADMIN_DIALOG_REMOVE, _("&Remove"), wxDefaultPosition, wxDefaultSize, 0 );
181     item4->Add( item6, 0, wxALIGN_CENTRE|wxALL, 5 );
182
183     item4->Add( 20, 20, 1, wxALIGN_CENTRE|wxALL, 5 );
184
185     wxButton *item7 = new wxButton( parent, wxID_OK, _("&Close"), wxDefaultPosition, wxDefaultSize, 0 );
186     item4->Add( item7, 0, wxALIGN_CENTRE|wxALL, 5 );
187
188 #ifdef __WXGTK__
189     wxButton *contextButton = new wxContextHelpButton( parent );
190     item4->Add( contextButton, 0, wxALIGN_CENTRE|wxALL, 5 );
191 #endif
192
193     item0->Add( item4, 0, wxGROW|wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxTOP|wxBOTTOM, 5 );
194     
195     item7->SetDefault(); // Make Close the default button
196
197     parent->SetAutoLayout( TRUE );
198     parent->SetSizer( item0 );
199     parent->Layout();
200     item0->Fit( parent );
201     //item0->SetSizeHints( parent );
202
203     // Add context-sensitive help text
204     parent->FindWindow( ecID_ADMIN_DIALOG_TREE)->SetHelpText(_("Displays the set of packages currently in the eCos component repository."));
205     parent->FindWindow( ecID_ADMIN_DIALOG_ADD)->SetHelpText(_("Adds the contents of an eCos package file to the eCos component repository."));
206     parent->FindWindow( ecID_ADMIN_DIALOG_REMOVE)->SetHelpText(_("Removes the currently selected package from the eCos component repository."));
207     parent->FindWindow( wxID_OK )->SetHelpText(_("Closes the dialog and saves any changes you have made."));
208
209 #if __WXGTK__
210     parent->FindWindow( wxID_CONTEXT_HELP )->SetHelpText(_("Invokes context-sensitive help for the clicked-on window."));
211 #endif
212
213 }
214
215 void ecAdminDialog::OnAdd(wxCommandEvent& event)
216 {
217     wxString defaultDir; // TODO
218     wxString defaultFile;
219     wxString wildcard = wxT("eCos Package Files (*.epk)|*.epk");
220     wxFileDialog dlg(this, _("Open eCos Package Files"), defaultDir, defaultFile, wildcard, wxOPEN|wxMULTIPLE);
221
222     if (wxID_OK == dlg.ShowModal ())
223     {
224         bool bRepositoryChanged = FALSE;
225         //POSITION posPathName = dlg.GetStartPosition ();
226         wxArrayString filenames;
227         dlg.GetPaths(filenames);
228         size_t i;
229         for (i = (size_t) 0; i < filenames.GetCount(); i++)
230         {
231             wxString strPathName(filenames[i]);
232
233             if (!wxFileExists(strPathName))
234             {
235                 wxString msg;
236                 msg.Printf(_("Cannot open %s"), (const wxChar*) strPathName);
237                 wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
238             }
239             else
240             {
241                 
242                 // get an eCos package distribution file
243                 
244                 // extract the licence file
245
246                 wxString strCommand;
247                 strCommand.Printf(wxT("add %s --extract_license"), (const wxChar*) strPathName);
248                 strCommand.Replace(wxT("\\"), wxT("/")); // backslashes -> forward slashes for Tcl_EvalFile
249                 EvalTclFile (3, strCommand, _("Adding package"));
250
251                 wxString strLicenseFile = m_strRepository + wxString(wxFILE_SEP_PATH) + wxT("pkgadd.txt");
252 #ifdef __WXMSW__
253                 strLicenseFile.Replace (wxT("/"), wxT("\\")); // forward slashes -> backslashes for Win32
254 #endif
255                 // read the license file
256
257                 wxFile fileLicenseFile;
258                 if (fileLicenseFile.Exists (strLicenseFile) && fileLicenseFile.Open (strLicenseFile, wxFile::read))
259                 {
260                     //TRACE (_T("License file found at %s\n"), strLicenseFile);
261                     const off_t dwLicenseLength = fileLicenseFile.Length ();
262                     char* pszBuffer = new char [dwLicenseLength + 1]; // allocate a buffer
263                     fileLicenseFile.Read ((void*) pszBuffer, dwLicenseLength);
264                     fileLicenseFile.Close ();
265                     wxRemoveFile (strLicenseFile); // delete the license file when read
266                     pszBuffer [dwLicenseLength] = 0; // terminate the string in the buffer
267                     wxString strLicenseText (pszBuffer); // copy into a wxString to convert to Unicode
268                     delete [] pszBuffer;
269 #ifdef __WXMSW__
270                     if (-1 == strLicenseText.Find (wxT("\r\n"))) // if the file has LF line endings...
271                         strLicenseText.Replace (_T("\n"), _T("\r\n")); // ... replace with CRLF line endings
272 #endif                    
273                     // display the license text
274                     
275                     ecLicenseDialog dlgLicense (strLicenseText, this, ecID_LICENSE_DIALOG, strPathName + _(" - Add Packages"));
276                     if (wxID_OK != dlgLicense.ShowModal ()) // if license not accepted by user
277                         continue; // try the next file
278                 }
279                 
280                 // add the contents of the package distribution file
281                 
282                 strCommand.Printf (wxT("add %s --accept_license"), (const wxChar*) strPathName);
283                 strCommand.Replace (wxT("\\"), wxT("/")); // backslashes -> forward slashes for Tcl_EvalFile
284                 if (! EvalTclFile (3, strCommand, _("Adding package")))  // if not successful
285                 {
286                     // try the next file
287                 }
288                 else
289                 {                
290                     bRepositoryChanged = TRUE;
291                 }
292             }
293         }
294         
295         // refresh the package tree only if necessary
296         
297         if (bRepositoryChanged && ! PopulatePackageTree (m_strRepository))
298         {
299         }
300     }
301 }
302
303 void ecAdminDialog::OnRemove(wxCommandEvent& event)
304 {
305     wxTreeCtrl* treeCtrl = (wxTreeCtrl*) FindWindow( ecID_ADMIN_DIALOG_TREE) ;
306
307     const wxTreeItemId hTreeItem = treeCtrl->GetSelection ();
308     if (! hTreeItem || !hTreeItem.IsOk())
309         return;
310     
311     if (wxYES != wxMessageBox (_("The selected package will be deleted from the repository. Core eCos packages may be restored only by reinstalling eCos.\n\nDo you wish to continue?"),
312         _("Remove Package"), wxYES_NO | wxICON_EXCLAMATION))
313         return;
314
315     ecAdminItemData* data = (ecAdminItemData*) treeCtrl->GetItemData (hTreeItem);
316
317     if (data) // if a package node is selected
318     {
319         // remove all package version nodes
320
321         wxString pstrPackage(data->m_string);
322         
323         bool bStatus = TRUE;
324         long cookie;
325         wxTreeItemId hChildItem = treeCtrl->GetFirstChild (hTreeItem, cookie);
326         while (hChildItem && bStatus)
327         {
328             const wxTreeItemId hNextChildItem = treeCtrl->GetNextSibling (hChildItem);                  
329             bStatus = RemovePackageVersion (hChildItem);
330             hChildItem = hNextChildItem;
331         }
332         
333         // remove the package node
334         
335         if (bStatus)
336         {
337             treeCtrl->Delete (hTreeItem);
338         }
339     }
340     else // a version node is selected
341     {
342         // remove the version node
343         
344         const wxTreeItemId hParentItem = treeCtrl->GetParent (hTreeItem);
345         wxASSERT (hParentItem && hParentItem.IsOk() );
346         if (RemovePackageVersion (hTreeItem) && ! treeCtrl->ItemHasChildren (hParentItem)) // if the only version was deleted
347         {
348             // remove the package node
349             
350             treeCtrl->Delete (hParentItem); 
351         }
352     }
353 }
354
355 void ecAdminDialog::OnClose(wxCommandEvent& event)
356 {
357     event.Skip();
358 }
359
360 bool ecAdminDialog::FindUserToolsPath()
361 {
362 #ifdef __WXMSW__
363     HKEY hKey;
364     if (ERROR_SUCCESS != RegOpenKeyEx (HKEY_CURRENT_USER, _T("Software\\eCos Configuration Tool\\Paths\\UserToolsDir"), 0, KEY_READ, &hKey))
365         return FALSE;
366     
367     TCHAR szBuffer [MAX_PATH + 1];
368     DWORD dwBufferLength = MAX_PATH + 1;
369     LONG lStatus = RegQueryValueEx (hKey, _T("Folder"), NULL, NULL, (LPBYTE) szBuffer, &dwBufferLength);
370     RegCloseKey (hKey);
371     if (ERROR_SUCCESS != lStatus)
372         return FALSE;
373     
374     m_strUserTools = szBuffer;
375     // TRACE (_T("User tools found at %s\n"), m_strUserTools);
376     return ! m_strUserTools.IsEmpty ();
377 #else
378     // wxMessageBox("Sorry, ecAdminDialog::FindUserToolsPath not implemented for this platform.");
379     return FALSE;
380 #endif
381 }
382
383 bool ecAdminDialog::RemovePackageVersion (wxTreeItemId hTreeItem)
384 {
385     wxTreeCtrl* treeCtrl = (wxTreeCtrl*) FindWindow( ecID_ADMIN_DIALOG_TREE) ;
386
387     const wxTreeItemId hParentItem = treeCtrl->GetParent (hTreeItem);
388     wxASSERT (hParentItem);
389
390     ecAdminItemData* data = (ecAdminItemData*) treeCtrl->GetItemData (hParentItem);
391
392     wxASSERT( data );
393
394     if (!data)
395         return FALSE;
396
397     wxString pstrPackage = data->m_string ;
398
399     wxString strCommand;
400     wxString itemText(treeCtrl->GetItemText (hTreeItem));
401     strCommand.Printf (wxT("remove %s --version %s"), (const wxChar*) pstrPackage, (const wxChar*) itemText);
402     if (! EvalTclFile (3, strCommand, wxT("Removing package"))) // if not successful
403         return false;
404     
405     treeCtrl->Delete (hTreeItem); // remove the selected item from the tree
406
407     return TRUE;
408 }
409
410 void ecAdminDialog::ClearPackageTree ()
411 {
412     wxTreeCtrl* treeCtrl = (wxTreeCtrl*) FindWindow( ecID_ADMIN_DIALOG_TREE) ;
413
414     wxTreeItemId hPackage = treeCtrl->GetRootItem ();
415     if (! hPackage.IsOk()) // if no packages in the tree...
416         return;     // ...nothing to do
417     
418     while (hPackage.IsOk())
419     {
420         const wxTreeItemId hNextPackage = treeCtrl->GetNextSibling(hPackage);
421         treeCtrl->Delete (hPackage);
422         hPackage = hNextPackage;
423     }
424 }
425
426 // Trivial handlers; otherwise CdlPackagesDatabaseBody::make asserts.
427 static void CdlErrorHandler (std::string message)
428 {
429 };
430
431 static void CdlWarningHandler (std::string message)
432 {
433 };
434
435
436 bool ecAdminDialog::PopulatePackageTree (const wxString& packageDatabase)
437 {
438     wxTreeCtrl* treeCtrl = (wxTreeCtrl*) FindWindow( ecID_ADMIN_DIALOG_TREE) ;
439
440     // delete any existing CDL database
441     
442     if (m_CdlPkgData)
443     {
444         delete m_CdlPkgData;
445         m_CdlPkgData = NULL;
446     }
447     
448     // load the package database
449     
450     try
451     {
452         // Cdl asserts unless the handlers are present.
453         m_CdlPkgData = CdlPackagesDatabaseBody::make (ecUtils::UnicodeToStdStr (packageDatabase), &CdlErrorHandler, &CdlWarningHandler);
454     }
455     catch (CdlStringException exception)
456     {
457         wxString strMessage;
458         strMessage.Printf (_("Error loading database:\n\n%s"), (const wxChar*) wxString (exception.get_message ().c_str ()));
459         wxMessageBox(strMessage, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
460         return FALSE;
461     }
462     catch (...)
463     {
464         wxMessageBox(_("Error loading database"), (const wxChar*) wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
465         return FALSE;
466     }
467     
468     // clear the old package tree
469     
470     ClearPackageTree ();
471     
472     // Add a root item
473     wxTreeItemId rootId = m_treeCtrl->AddRoot(_("Packages"), 0, -1);
474
475     // populate the new package tree
476     
477     const std::vector<std::string>& packages = m_CdlPkgData->get_packages ();
478     for (std::vector<std::string>::const_iterator package = packages.begin (); package != packages.end (); package++)
479     {
480         // add a package node
481         
482         wxTreeItemId hPackage = treeCtrl->AppendItem (treeCtrl->GetRootItem(), wxString (m_CdlPkgData->get_package_aliases (*package) [0].c_str ()));
483         treeCtrl->SetItemData (hPackage, new ecAdminItemData(wxString (package->c_str ())));
484         treeCtrl->SetItemImage (hPackage, 0, wxTreeItemIcon_Normal);
485         treeCtrl->SetItemImage (hPackage, 0, wxTreeItemIcon_Selected);
486         treeCtrl->SetItemImage (hPackage, 0, wxTreeItemIcon_Expanded);
487         treeCtrl->SetItemImage (hPackage, 0, wxTreeItemIcon_SelectedExpanded);
488         
489         const std::vector<std::string>& versions = m_CdlPkgData->get_package_versions (* package);
490         for (std::vector<std::string>::const_iterator version = versions.begin (); version != versions.end (); version++)
491         {
492             // add a version node
493             const wxTreeItemId hVersion = treeCtrl->AppendItem ( hPackage, wxString (version->c_str ()));
494             treeCtrl->SetItemImage (hVersion, 1, wxTreeItemIcon_Normal);
495             treeCtrl->SetItemImage (hVersion, 1, wxTreeItemIcon_Selected);
496             treeCtrl->SetItemImage (hVersion, 1, wxTreeItemIcon_Expanded);
497             treeCtrl->SetItemImage (hVersion, 1, wxTreeItemIcon_SelectedExpanded);
498         }
499         treeCtrl->SortChildren (hPackage); // sort the version nodes
500     }
501     
502     treeCtrl->SortChildren (treeCtrl->GetRootItem()); // sort the package nodes
503     treeCtrl->Expand(treeCtrl->GetRootItem());
504     
505     return TRUE;
506 }
507
508
509 bool ecAdminDialog::EvalTclFile(int nargc, const wxString& Argv, const wxString& msg)
510 {
511     wxProgressDialog dlgWait(msg, _("Please wait..."), 100, this);
512
513     dlgWait.Update(50);
514
515 //TRACE (_T("Evaluating ecosadmin.tcl %s\n"), pszArgv);
516
517     // set up the data structure which is passed to the Tcl thread
518
519     wxString strArgc;
520     strArgc.Printf (wxT("%d"), nargc);
521     std::string argv0 = ecUtils::UnicodeToStdStr (m_strRepository) + "/ecosadmin.tcl";
522     std::string argv = ecUtils::UnicodeToStdStr (Argv);
523     std::string argc = ecUtils::UnicodeToStdStr (strArgc);
524
525     Tcl_Interp * interp = Tcl_CreateInterp ();
526
527 #ifdef __WXMSW__
528     Tcl_Channel outchan = Tcl_OpenFileChannel (interp, "nul", "a+", 777);
529     Tcl_SetStdChannel (outchan, TCL_STDOUT); // direct standard output to NUL:
530 #endif
531
532     const char * pszStatus = Tcl_SetVar (interp, "argv0", (char*) argv0.c_str(), 0);
533     pszStatus = Tcl_SetVar (interp, "argv", (char*) argv.c_str(), 0);
534     pszStatus = Tcl_SetVar (interp, "argc", (char*) argc.c_str(), 0);
535     pszStatus = Tcl_SetVar (interp, "gui_mode", "1", 0); // return errors in result string
536     int nStatus = Tcl_EvalFile (interp, (char*) argv0.c_str());
537     const char* result = Tcl_GetStringResult (interp);
538
539 #ifdef __WXMSW__
540     Tcl_SetStdChannel (NULL, TCL_STDOUT);
541     Tcl_UnregisterChannel (interp, outchan);
542 #endif
543
544     Tcl_DeleteInterp (interp);
545
546     wxString strErrorMessage (result);
547
548     // report any error
549     if (! strErrorMessage.IsEmpty ())
550     {
551         wxString msg (_("Command execution error:\n\n") + strErrorMessage);
552         wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
553         return FALSE;
554     }
555     else if (TCL_OK != nStatus)
556     {
557         wxString msg (_("Command execution error"));
558         wxMessageBox(msg, wxGetApp().GetSettings().GetAppName(), wxICON_EXCLAMATION|wxOK);
559     return FALSE;
560     }
561
562     return TRUE;
563 }