1 //####COPYRIGHTBEGIN####
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
6 // This program is part of the eCos host tools.
8 // This program is free software; you can redistribute it and/or modify it
9 // under the terms of the GNU General Public License as published by the Free
10 // Software Foundation; either version 2 of the License, or (at your option)
13 // This program is distributed in the hope that it will be useful, but WITHOUT
14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 // You should have received a copy of the GNU General Public License along with
19 // this program; if not, write to the Free Software Foundation, Inc.,
20 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 // ----------------------------------------------------------------------------
24 //####COPYRIGHTEND####
25 // PkgAdminDlg.cpp : implementation file
31 #include "PkgAdminDlg.h"
32 #include "PkgAdminLicenseDlg.h"
33 #include "PkgAdminTclWaitDlg.h"
38 static char THIS_FILE[] = __FILE__;
41 /////////////////////////////////////////////////////////////////////////////
42 // CPkgadminAboutDlg dialog used for App About
44 class CPkgadminAboutDlg : public CDialog
50 //{{AFX_DATA(CPkgadminAboutDlg)
51 enum { IDD = IDD_PKGADMIN_ABOUTBOX };
54 // ClassWizard generated virtual function overrides
55 //{{AFX_VIRTUAL(CPkgadminAboutDlg)
57 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
62 //{{AFX_MSG(CPkgadminAboutDlg)
67 CPkgadminAboutDlg::CPkgadminAboutDlg() : CDialog(CPkgadminAboutDlg::IDD)
69 //{{AFX_DATA_INIT(CPkgadminAboutDlg)
73 void CPkgadminAboutDlg::DoDataExchange(CDataExchange* pDX)
75 CDialog::DoDataExchange(pDX);
76 //{{AFX_DATA_MAP(CPkgadminAboutDlg)
80 BEGIN_MESSAGE_MAP(CPkgadminAboutDlg, CDialog)
81 //{{AFX_MSG_MAP(CPkgadminAboutDlg)
82 // No message handlers
86 /////////////////////////////////////////////////////////////////////////////
87 // CPkgAdminDlg dialog
89 CPkgAdminDlg::CPkgAdminDlg(LPCTSTR pszRepository,LPCTSTR pszUserTools)
90 : CeCosDialog(CPkgAdminDlg::IDD, NULL)
92 //{{AFX_DATA_INIT(CPkgAdminDlg)
93 // NOTE: the ClassWizard will add member initialization here
95 // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
97 m_strRepository=pszRepository;
100 m_strUserTools=pszUserTools;
105 void CPkgAdminDlg::DoDataExchange(CDataExchange* pDX)
107 CeCosDialog::DoDataExchange(pDX);
108 //{{AFX_DATA_MAP(CPkgAdminDlg)
109 DDX_Control(pDX, IDC_PKGADMIN_REMOVE, m_btnRemove);
110 DDX_Control(pDX, IDC_PKGADMIN_TREE, m_ctrlPackageTree);
114 BEGIN_MESSAGE_MAP(CPkgAdminDlg, CeCosDialog)
115 //{{AFX_MSG_MAP(CPkgAdminDlg)
118 ON_WM_QUERYDRAGICON()
119 ON_BN_CLICKED(IDC_PKGADMIN_REMOVE, OnPkgadminRemove)
121 ON_BN_CLICKED(IDC_PKGADMIN_ADD, OnPkgadminAdd)
122 ON_BN_CLICKED(IDCLOSE, OnClose)
123 ON_BN_CLICKED(IDC_PKGADMIN_REPOSITORY, OnPkgadminRepository)
124 ON_NOTIFY(TVN_SELCHANGED, IDC_PKGADMIN_TREE, OnSelchangedPkgadminTree)
128 /////////////////////////////////////////////////////////////////////////////
129 // CPkgAdminDlg message handlers
131 BOOL CPkgAdminDlg::OnInitDialog()
133 CeCosDialog::OnInitDialog();
135 if(this==AfxGetApp()->m_pMainWnd){ // only if the dialog is the application
136 // Add "About..." menu item to system menu.
138 // IDM_ABOUTBOX must be in the system command range.
139 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
140 ASSERT(IDM_ABOUTBOX < 0xF000);
142 CMenu* pSysMenu = GetSystemMenu(FALSE);
143 if (pSysMenu != NULL)
145 CString strAboutMenu;
146 strAboutMenu.LoadString(IDS_ABOUTBOX);
147 if (!strAboutMenu.IsEmpty())
149 pSysMenu->AppendMenu(MF_SEPARATOR);
150 pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
154 // Set the icon for this dialog. The framework does this automatically
155 // when the application's main window is not a dialog
156 SetIcon(m_hIcon, TRUE); // Set big icon
158 // The following AppWizard-generated call was causing the 32x32 icon to
159 // be resized for use as a 16x16 icon. Removing the call causes the
160 // correct 16x16 icon to be displayed.
161 // SetIcon(m_hIcon, FALSE); // Set small icon
163 // TODO: Add extra initialization here
165 // setup the repsoitory location
167 if (m_strRepository.IsEmpty()) // if the repository cannot be located
169 OnPkgadminRepository (); // prompt the user for the repository location
170 if (m_strRepository.IsEmpty ())
172 PostMessage (WM_COMMAND,IDCANCEL);
177 GetDlgItem(IDC_PKGADMIN_REPOSITORY)->ShowWindow(SW_HIDE);
180 // setup the path to the user tools (tar and gunzip)
182 if ((! m_strUserTools.IsEmpty()) || FindUserToolsPath ()) // if the user tools can be located
184 // add the user tools to the PATH environment variable
185 const DWORD nLength = GetEnvironmentVariable (_T("PATH"), NULL, 0) + 1;
186 TCHAR * pszOldPath = new TCHAR [nLength];
187 GetEnvironmentVariable (_T("PATH"), pszOldPath, nLength);
188 SetEnvironmentVariable (_T("PATH"), CString (pszOldPath) + _T(";") + m_strUserTools);
189 delete [] pszOldPath;
192 // setup the package tree image list
194 m_ilTreeIcons.Create (IDB_PKGADMIN_TREEICONS, 16, 1, RGB (0,128,128));
195 m_ctrlPackageTree.SetImageList (&m_ilTreeIcons, TVSIL_NORMAL);
197 // populate the package tree
199 while (! PopulatePackageTree (m_strRepository))
201 m_strRepository = _T("");
202 OnPkgadminRepository (); // prompt the user for the repository location
203 if (m_strRepository.IsEmpty ()) // if dialog was cancelled
210 return TRUE; // return TRUE unless you set the focus to a control
213 void CPkgAdminDlg::OnSysCommand(UINT nID, LPARAM lParam)
215 if ((nID & 0xFFF0) == IDM_ABOUTBOX)
217 CPkgadminAboutDlg dlgAbout;
222 CeCosDialog::OnSysCommand(nID, lParam);
226 // If you add a minimize button to your dialog, you will need the code below
227 // to draw the icon. For MFC applications using the document/view model,
228 // this is automatically done for you by the framework.
230 void CPkgAdminDlg::OnPaint()
234 CPaintDC dc(this); // device context for painting
236 SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
238 // Center icon in client rectangle
239 int cxIcon = GetSystemMetrics(SM_CXICON);
240 int cyIcon = GetSystemMetrics(SM_CYICON);
242 GetClientRect(&rect);
243 int x = (rect.Width() - cxIcon + 1) / 2;
244 int y = (rect.Height() - cyIcon + 1) / 2;
247 dc.DrawIcon(x, y, m_hIcon);
251 CeCosDialog::OnPaint();
255 // The system calls this to obtain the cursor to display while the user drags
256 // the minimized window.
257 HCURSOR CPkgAdminDlg::OnQueryDragIcon()
259 return (HCURSOR) m_hIcon;
262 // Trivial handlers; otherwise CdlPackagesDatabaseBody::make asserts.
263 void CdlErrorHandler (std::string message)
267 void CdlWarningHandler (std::string message)
272 bool CPkgAdminDlg::PopulatePackageTree(LPCTSTR pszPackagesPath)
274 // delete any existing CDL database
282 // load the package database
286 // Cdl asserts unless the handlers are present.
288 m_CdlPkgData = CdlPackagesDatabaseBody::make (UnicodeToStdStr (pszPackagesPath), &CdlErrorHandler, &CdlWarningHandler);
290 m_CdlPkgData = CdlPackagesDatabaseBody::make (UnicodeToStdStr (pszPackagesPath));
293 catch (CdlStringException exception)
296 strMessage.Format (_T("Error loading database:\n\n%s"), CString (exception.get_message ().c_str ()));
297 AfxMessageBox (strMessage);
302 AfxMessageBox (_T("Error loading database"));
306 // clear the old package tree
310 // populate the new package tree
312 const std::vector<std::string>& packages = m_CdlPkgData->get_packages ();
313 for (std::vector<std::string>::const_iterator package = packages.begin (); package != packages.end (); package++)
315 // add a package node
317 TRACE (_T("Adding package %s:"), CString (package->c_str ()));
318 HTREEITEM hPackage = m_ctrlPackageTree.InsertItem (CString (m_CdlPkgData->get_package_aliases (*package) [0].c_str ()));
319 m_ctrlPackageTree.SetItemData (hPackage, (DWORD) new CString (package->c_str ()));
320 m_ctrlPackageTree.SetItemImage (hPackage, 0, 0);
322 const std::vector<std::string>& versions = m_CdlPkgData->get_package_versions (* package);
323 for (std::vector<std::string>::const_iterator version = versions.begin (); version != versions.end (); version++)
325 // add a version node
327 TRACE (_T(" %s"), CString (version->c_str ()));
328 const HTREEITEM hVersion = m_ctrlPackageTree.InsertItem (CString (version->c_str ()), hPackage);
329 m_ctrlPackageTree.SetItemImage (hVersion, 1, 1);
332 m_ctrlPackageTree.SortChildren (hPackage); // sort the version nodes
335 m_ctrlPackageTree.SortChildren (NULL); // sort the package nodes
337 if(this==AfxGetApp()->m_pMainWnd){ // if the dialog is the application
338 // update the caption bar
339 CString strCaption (m_strRepository);
340 strCaption.Replace (_TCHAR('/'), _TCHAR('\\'));
341 strCaption += _T(" - eCos Package Administration Tool");
342 SetWindowText (strCaption);
348 void CPkgAdminDlg::OnPkgadminRemove()
350 const HTREEITEM hTreeItem = m_ctrlPackageTree.GetSelectedItem ();
354 if (IDYES != CWnd::MessageBox (_T("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?"),
355 _T("Remove Package"), MB_YESNO | MB_ICONEXCLAMATION))
358 const CString * pstrPackage = (const CString *) m_ctrlPackageTree.GetItemData (hTreeItem);
359 if (pstrPackage) // if a package node is selected
361 // remove all package version nodes
364 HTREEITEM hChildItem = m_ctrlPackageTree.GetChildItem (hTreeItem);
365 while (hChildItem && bStatus)
367 const HTREEITEM hNextChildItem = m_ctrlPackageTree.GetNextSiblingItem (hChildItem);
368 bStatus = RemovePackageVersion (hChildItem);
369 hChildItem = hNextChildItem;
372 // remove the package node
377 m_ctrlPackageTree.DeleteItem (hTreeItem);
380 else // a version node is selected
382 // remove the version node
384 const HTREEITEM hParentItem = m_ctrlPackageTree.GetParentItem (hTreeItem);
385 ASSERT (hParentItem);
386 if (RemovePackageVersion (hTreeItem) && ! m_ctrlPackageTree.ItemHasChildren (hParentItem)) // if the only version was deleted
388 // remove the package node
391 m_ctrlPackageTree.DeleteItem (hParentItem);
396 void CPkgAdminDlg::ClearPackageTree()
398 HTREEITEM hPackage = m_ctrlPackageTree.GetRootItem ();
399 if (! hPackage) // if no packages in the tree...
400 return; // ...nothing to do
404 const HTREEITEM hNextPackage = m_ctrlPackageTree.GetNextSiblingItem (hPackage);
405 TRACE (_T("Deleting package %s\n"), * ((CString *) m_ctrlPackageTree.GetItemData (hPackage)));
406 delete (CString *) m_ctrlPackageTree.GetItemData (hPackage);
407 m_ctrlPackageTree.DeleteItem (hPackage);
408 hPackage = hNextPackage;
412 void CPkgAdminDlg::OnDestroy()
414 CeCosDialog::OnDestroy();
416 // free memory allocated to the tree item data CStrings
420 // free memory allocated to the CDL database
427 void CPkgAdminDlg::OnPkgadminAdd()
429 CFileDialog dlg (TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT, _T("eCos Package Files (*.epk)|*.epk||"), GetParent ());
430 TCHAR szBuffer [MAX_PATH * 16] = _T("");
431 dlg.m_ofn.lpstrFile = szBuffer;
432 dlg.m_ofn.nMaxFile = MAX_PATH * 16;
433 dlg.m_ofn.lpstrTitle = _T("Open eCos Package Files");
434 if (IDOK == dlg.DoModal ())
436 bool bRepositoryChanged = false;
437 POSITION posPathName = dlg.GetStartPosition ();
440 // get an eCos package distribution file
442 CString strPathName = dlg.GetNextPathName (posPathName);
444 // extract the licence file
447 strCommand.Format (_T("add %s --extract_license"), strPathName);
448 strCommand.Replace (_TCHAR('\\'), _TCHAR('/')); // backslashes -> forward slashes for Tcl_EvalFile
449 EvalTclFile (3, strCommand);
450 CString strLicenseFile = m_strRepository + _T("/pkgadd.txt");
451 strLicenseFile.Replace (_TCHAR('/'), _TCHAR('\\')); // forward slashes -> backslashes for Win32
453 // read the license file
455 CFile fileLicenseFile;
456 if (fileLicenseFile.Open (strLicenseFile, CFile::modeRead))
458 TRACE (_T("License file found at %s\n"), strLicenseFile);
459 const DWORD dwLicenseLength = fileLicenseFile.GetLength ();
460 char * pszBuffer = new char [dwLicenseLength + 1]; // allocate a buffer
461 fileLicenseFile.Read (pszBuffer, dwLicenseLength);
462 fileLicenseFile.Close ();
463 CFile::Remove (strLicenseFile); // delete the license file when read
464 pszBuffer [dwLicenseLength] = NULL; // terminate the string in the buffer
465 CString strLicenseText (pszBuffer); // copy into a CString to convert to Unicode
467 if (-1 == strLicenseText.Find (_T("\r\n"))) // if the file has LF line endings...
468 strLicenseText.Replace (_T("\n"), _T("\r\n")); // ... replace with CRLF line endings
470 // display the license text
472 CPkgAdminLicenseDlg dlgLicense (this);
473 dlgLicense.m_strLicense = strLicenseText;
474 dlgLicense.SetCaption (strPathName + _T(" - Add Packages"));
475 if (IDOK != dlgLicense.DoModal ()) // if license not accepted by user
476 continue; // try the next file
479 // add the contents of the package distribution file
481 strCommand.Format (_T("add %s --accept_license"), strPathName);
482 strCommand.Replace (_TCHAR('\\'), _TCHAR('/')); // backslashes -> forward slashes for Tcl_EvalFile
483 if (! EvalTclFile (3, strCommand)) // if not successful
484 continue; // try the next file
486 bRepositoryChanged = true;
489 // refresh the package tree only if necessary
491 if (bRepositoryChanged && ! PopulatePackageTree (m_strRepository))
496 bool CPkgAdminDlg::EvalTclFile(int nArgc, LPCTSTR pszArgv)
498 CPkgAdminTclWaitDlg dlgWait;
500 TRACE (_T("Evaluating ecosadmin.tcl %s\n"), pszArgv);
502 // set up the data structure which is passed to the Tcl thread
505 strArgc.Format (_T("%d"), nArgc);
506 std::string argv0 = UnicodeToStdStr (m_strRepository) + "/ecosadmin.tcl";
507 std::string argv = UnicodeToStdStr (pszArgv);
508 std::string argc = UnicodeToStdStr (strArgc);
509 dlgWait.etsInfo.argv0 = (char *) argv0.c_str ();
510 dlgWait.etsInfo.argv = (char *) argv.c_str ();
511 dlgWait.etsInfo.argc = (char *) argc.c_str ();
513 // display the 'please wait' dialog
514 // the Tcl command is invoked from CPkgAdminTclWaitDlg::OnCreate()
520 // retrieve status information from the data structure
522 int nStatus = dlgWait.etsInfo.status;
523 CString strErrorMessage (dlgWait.etsInfo.result);
527 if (! strErrorMessage.IsEmpty ())
529 AfxMessageBox (_T("Command execution error:\n\n") + strErrorMessage);
532 else if (TCL_OK != nStatus)
534 AfxMessageBox (_T("Command execution error"));
541 bool CPkgAdminDlg::RemovePackageVersion(HTREEITEM hTreeItem)
543 const HTREEITEM hParentItem = m_ctrlPackageTree.GetParentItem (hTreeItem);
544 ASSERT (hParentItem);
545 CString * pstrPackage = (CString *) m_ctrlPackageTree.GetItemData (hParentItem);
546 ASSERT (pstrPackage);
548 strCommand.Format (_T("remove %s --version %s"), * pstrPackage, m_ctrlPackageTree.GetItemText (hTreeItem));
549 if (! EvalTclFile (3, strCommand)) // if not successful
552 m_ctrlPackageTree.DeleteItem (hTreeItem); // remove the selected item from the tree
556 void CPkgAdminDlg::OnPkgadminRepository()
558 CFileDialog dlg (TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, _T("eCos Package Database Files (ecos.db)|ecos.db||"), GetParent ());
559 dlg.m_ofn.lpstrTitle = _T("Open eCos Package Database File");
564 nStatus = dlg.DoModal ();
567 const CString strPathName = dlg.GetPathName ();
568 const int nPathNameIndex = strPathName.ReverseFind (_TCHAR('\\'));
569 ASSERT (nPathNameIndex != -1);
570 m_strRepository = strPathName.Mid (0, nPathNameIndex);
571 m_strRepository.Replace (_TCHAR('\\'), _TCHAR('/'));
574 while ((IDOK == nStatus) && ! PopulatePackageTree (m_strRepository));
577 void CPkgAdminDlg::OnSelchangedPkgadminTree(NMHDR*, LRESULT* pResult)
579 //NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
581 // enable the remove button only if a node is selected
582 m_btnRemove.EnableWindow (NULL != m_ctrlPackageTree.GetSelectedItem ());
587 std::string CPkgAdminDlg::UnicodeToStdStr(LPCTSTR str)
589 int nLength = 1 + _tcslen (str);
590 char * pszString = new char [nLength];
593 WideCharToMultiByte (CP_ACP, 0, str, -1, pszString, nLength, NULL, NULL);
595 strcpy (pszString, str);
598 std::string stdstr = std::string (pszString);
603 bool CPkgAdminDlg::FindUserToolsPath()
606 if (ERROR_SUCCESS != RegOpenKeyEx (HKEY_CURRENT_USER, _T("Software\\Red Hat\\eCos\\Configuration Tool\\User Tools"), 0, KEY_READ, &hKey))
609 TCHAR szBuffer [MAX_PATH + 1];
610 DWORD dwBufferLength = MAX_PATH + 1;
611 LONG lStatus = RegQueryValueEx (hKey, _T("Folder"), NULL, NULL, (LPBYTE) szBuffer, &dwBufferLength);
613 if (ERROR_SUCCESS != lStatus)
616 m_strUserTools = szBuffer;
617 TRACE (_T("User tools found at %s\n"), m_strUserTools);
618 return ! m_strUserTools.IsEmpty ();