home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / SHELL.PAK / SHELLWIN.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  13.5 KB  |  425 lines

  1. //----------------------------------------------------------------------------
  2. //  Project Shell
  3. //  Borland International
  4. //  Copyright ⌐ 1995, 1996 Borland International. All Rights Reserved.
  5. //
  6. //  SUBSYSTEM:    shell.exe Application
  7. //  FILE:         shellwin.cpp
  8. //  AUTHOR:       The OWL Team
  9. //
  10. //  OVERVIEW
  11. //  ~~~~~~~~
  12. //  Source file for implementation of TShellWindow (TWindow).
  13. //
  14. //----------------------------------------------------------------------------
  15.  
  16. #include <owl/pch.h>
  17.  
  18. #include "shellapp.h"
  19. #include "mdichild.h"
  20. #include "mdiclien.h"
  21. #include "shellwin.h"
  22.  
  23. #include <stdio.h>
  24.  
  25.  
  26. //{{TShellWindow Implementation}}
  27.  
  28.  
  29. //
  30. // Build a response table for all messages/commands handled
  31. // by TShellWindow derived from TWindow.
  32. //
  33. DEFINE_RESPONSE_TABLE1(TShellWindow, TWindow)
  34. //{{ShellWindowRSP_TBL_BEGIN}}
  35.   EV_WM_CREATE,
  36.   EV_WM_GETMINMAXINFO,
  37.   EV_WM_SIZE,
  38.   EV_WM_LBUTTONUP,
  39.   EV_WM_RBUTTONUP,
  40.   EV_WM_LBUTTONDBLCLK,
  41.   EV_WM_CHAR,
  42. //{{ShellWindowRSP_TBL_END}}
  43. END_RESPONSE_TABLE;
  44.  
  45.  
  46. //--------------------------------------------------------
  47. // TShellWindow
  48. // ~~~~~~~~~~~
  49. // Construction/Destruction handling.
  50. //
  51. TShellWindow::TShellWindow(TWindow* parent, TShellItem* item,
  52.   const char far* title, TModule* module)
  53. :
  54.   TWindow(parent, title, module),
  55.   ItemGrids(0), ClientRectWidth(0), ItemsPerRow(0), SelectedItem(-1)
  56. {
  57.   if (item)
  58.     Folder = TShellItem(*item);
  59.   else
  60.     Folder = TShellItem(TShellItem::Desktop);
  61.  
  62.   ItemGrids = new TArray<ItemGrid>(10, 0, 10);
  63. }
  64.  
  65. TShellWindow::~TShellWindow()
  66. {
  67.   Destroy();
  68.   delete ItemGrids;
  69. }
  70.  
  71.  
  72. //
  73. // Paint routine for Window, Printer, and PrintPreview for an TWindow client.
  74. //
  75. void TShellWindow::Paint(TDC& dc, bool, TRect& rect)
  76. {
  77.   TShellApp* theApp = TYPESAFE_DOWNCAST(GetApplication(), TShellApp);
  78.   if (theApp) {
  79.     LOGFONT logFont;
  80.     SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof (logFont), &logFont, 0);
  81.     TFont font(&logFont);
  82.     dc.SelectObject(font);
  83.     TShellItem item;
  84.     ComputeItemGrids();
  85.     int cnt = 0;
  86.     for (TArrayIterator<ItemGrid> i(*ItemGrids); i; i++, cnt++)
  87.       if (i.Current().Grid.Touches(rect)) {
  88.         item = *CONST_CAST(TShellItem*, &i.Current().Item);
  89.         dc.DrawIcon(i.Current().IconPt, item.GetIcon());
  90.         DrawIconTitle(dc, item.GetDisplayName(), i.Current().TitlePt.x,
  91.                       i.Current().TitlePt.y, i.Current().Grid.Width());
  92.         if (SelectedItem == cnt)
  93.           dc.InvertRect(i.Current().Grid);
  94.       }
  95.   }
  96. }
  97.  
  98. void TShellWindow::ComputeItemGrids()
  99. {
  100.   if (!ClientRectWidth || ClientRectWidth != GetClientRect().Width()) {
  101.     ClientRectWidth = GetClientRect().Width();
  102.     int iconWidth  = ::GetSystemMetrics(SM_CXICON);
  103.     int iconHeight = ::GetSystemMetrics(SM_CYICON);
  104.     int gridWidth  = ::GetSystemMetrics(SM_CXICONSPACING);
  105.     int gridHeight = ::GetSystemMetrics(SM_CYICONSPACING);
  106.  
  107.     int x = IconSpacingX;
  108.     int y = IconSpacingY;
  109.     ItemGrids->Flush();
  110.     TShellItem item;
  111.     for (TShellItemIterator i(Folder, *this,
  112.          TShellItemIterator::Folders | TShellItemIterator::NonFolders);
  113.          i.Valid(); x += gridWidth + IconSpacingX) {
  114.       item = i++;
  115.       if (x + gridWidth > ClientRectWidth) {
  116.         x = IconSpacingX;
  117.         y += gridHeight + IconSpacingY;
  118.       }
  119.       ItemGrids->Add(ItemGrid(item, TRect(TPoint(x, y), TSize(gridWidth, gridHeight)),
  120.                      TPoint(x+((gridWidth-iconWidth)/2), y), TPoint(x, y+iconHeight)));
  121.     }
  122.   }
  123. }
  124.  
  125. void TShellWindow::DrawIconTitle(TDC& dc, TString& name, int x, int y, int gridWidth)
  126. {
  127.   int length = name.Length();
  128.  
  129.   TSize size = dc.GetTextExtent(name, length);
  130.   if (size.cx <= gridWidth) {
  131.      dc.TextOut(x+(gridWidth - size.cx)/2, y, name);
  132.      return;
  133.   }
  134.  
  135.   const char* begin = STATIC_CAST(const char*, name);
  136.   const char* end = 0;
  137.   const char* prevEnd;
  138.   TEXTMETRIC metrics;
  139.   dc.GetTextMetrics(metrics);
  140.   int lineHeight = metrics.tmHeight + metrics.tmExternalLeading;
  141.  
  142.   for (int i = 0; i <= length; i++) {
  143.      if (STATIC_CAST(const char*, name)[i] == 0 || STATIC_CAST(const char*, name)[i] == ' ') {
  144.         prevEnd = end;
  145.         end = STATIC_CAST(const char*, name) + i - 1;
  146.         size = dc.GetTextExtent(begin, end - begin + 1);
  147.         if (size.cx > gridWidth) { // restore to previous and print
  148.           if (!prevEnd)   // no previous, just a word too long to fit
  149.         DrawLongWord(dc, x, y, gridWidth, begin, end);
  150.       else { // restore to previous and print
  151.              end = prevEnd;
  152.              i = end - STATIC_CAST(const char*, name) + 1;
  153.              size = dc.GetTextExtent(begin, end - begin + 1);
  154.              dc.TextOut(x+(gridWidth - size.cx)/2, y, begin, end - begin + 1);
  155.           }
  156.           y += lineHeight;
  157.           while (STATIC_CAST(const char*, name)[i] == ' ')
  158.              i++;
  159.           begin = STATIC_CAST(const char*, name) + i;
  160.           end = 0;
  161.         }
  162.      }
  163.   }
  164.   size = dc.GetTextExtent(begin, ::strlen(begin));
  165.         if (size.cx > gridWidth) {
  166.       end = begin + ::strlen(begin) - 1;
  167.       DrawLongWord(dc, x, y, gridWidth, begin, end);
  168.     }
  169.     else
  170.       dc.TextOut(x+(gridWidth - size.cx)/2, y, begin);
  171. }
  172.  
  173. void TShellWindow::DrawLongWord(TDC& dc, int x, int y, int gridWidth, const char* begin, const char* end)
  174. {
  175.   TSize size;
  176.  
  177.   // word is too long, print with ellipse
  178.   char* longWord = new char[end - begin + 4];
  179.   ::strncpy(longWord, begin, end - begin + 1);
  180.   longWord[end - begin + 1] = 0;
  181.   int length = ::strlen(longWord);
  182.   int j = 0;
  183.   do {
  184.     ::strcpy(longWord + length - ++j, "..."); // knock off 1 char
  185.     size = dc.GetTextExtent(longWord, ::strlen(longWord));
  186.   } while (size.cx > gridWidth);
  187.   dc.TextOut(x+(gridWidth - size.cx)/2, y, longWord);
  188. }
  189.  
  190. void TShellWindow::DisplayProperties(TShellItem& item)
  191. {
  192.   char* exeTypeStr[] = {"NonExecutable",
  193.                         "WindowsNE",
  194.                         "WindowsPE",
  195.                         "MSDOS",
  196.                         "Win32Console"};
  197.   char msg[1024];
  198.  
  199.   ::strcpy(msg,   "Full Name:  ");
  200.   ::strcat(msg, item.GetDisplayName(TShellItem::ForParsing));
  201.   ::strcat(msg, "\nTypename:  ");
  202.   ::strcat(msg, item.GetTypeName());
  203.   ::strcat(msg, "\nExeType:  ");
  204.   uint major, minor;
  205.   TShellItem::TExeKind exeKind = item.GetExeType(&major, &minor);
  206.   ::strcat(msg, exeTypeStr[exeKind]);
  207.   if (exeKind != TShellItem::NonExecutable) {
  208.     char cMajor[10];
  209.     char cMinor[10];
  210.     ::wsprintf(cMajor, "%u", major);
  211.     ::wsprintf(cMinor, "%u", minor);
  212.     ::strcat(msg, ", Version = ");
  213.     ::strcat(msg, cMajor);
  214.     ::strcat(msg, ".");
  215.     ::strcat(msg, cMinor);
  216.   }
  217.   ::strcat(msg, "\nCanBeCopied?  ");
  218.   ::strcat(msg, (item.CanBeCopied())? "Yes": "No");
  219.   ::strcat(msg, "\nCanBeDeleted?  ");
  220.   ::strcat(msg, (item.CanBeDeleted())? "Yes": "No");
  221.   ::strcat(msg, "\nCanCreateShortcut?  ");
  222.   ::strcat(msg, (item.CanCreateShortcut())? "Yes": "No");
  223.   ::strcat(msg, "\nCanBeMoved?  ");
  224.   ::strcat(msg, (item.CanBeMoved())? "Yes": "No");
  225.   ::strcat(msg, "\nCanBeRenamed?  ");
  226.   ::strcat(msg, (item.CanBeRenamed())? "Yes": "No");
  227.   ::strcat(msg, "\nIsADropTarget?  ");
  228.   ::strcat(msg, (item.IsADropTarget())? "Yes": "No");
  229.   ::strcat(msg, "\nHasAPropertySheet?  ");
  230.   ::strcat(msg, (item.HasAPropertySheet())? "Yes": "No");
  231.   ::strcat(msg, "\nDisplayGhosted?  ");
  232.   ::strcat(msg, (item.DisplayGhosted())? "Yes": "No");
  233.   ::strcat(msg, "\nIsShortcut?  ");
  234.   ::strcat(msg, (item.IsShortcut())? "Yes": "No");
  235.   if (item.IsShortcut()) {
  236.     TShellItem resolvedItem = item.ResolveShortcut(*this);
  237.     ::strcat(msg, ", resolves to:  ");
  238.     ::strcat(msg, resolvedItem.GetDisplayName(TShellItem::ForParsing));
  239.   }
  240.   ::strcat(msg, "\nIsReadOnly?  ");
  241.   ::strcat(msg, (item.IsReadOnly())? "Yes": "No");
  242.   ::strcat(msg, "\nIsShared?  ");
  243.   ::strcat(msg, (item.IsShared())? "Yes": "No");
  244.   ::strcat(msg, "\nContainsSubFolder?  ");
  245.   ::strcat(msg, (item.ContainsSubFolder())? "Yes": "No");
  246.   ::strcat(msg, "\nContainsFileSystemFolder?  ");
  247.   ::strcat(msg, (item.ContainsFileSystemFolder())? "Yes": "No");
  248.   ::strcat(msg, "\nIsPartOfFileSystem?  ");
  249.   ::strcat(msg, (item.IsPartOfFileSystem())? "Yes": "No");
  250.   ::strcat(msg, "\nIsFolder?  ");
  251.   ::strcat(msg, (item.IsFolder())? "Yes": "No");
  252.   ::strcat(msg, "\nCanBeRemoved?  ");
  253.   ::strcat(msg, (item.CanBeRemoved())? "Yes": "No");
  254.   ::strcat(msg, "\nIsDesktop?  ");
  255.   ::strcat(msg, (item.IsDesktop())? "Yes": "No");
  256.   MessageBox(msg, item.GetDisplayName(), MB_OK | MB_ICONINFORMATION);
  257. }
  258.  
  259. int TShellWindow::ComputeItemsPerRow()
  260. {
  261.   int gridWidth  = ::GetSystemMetrics(SM_CXICONSPACING);
  262.   int x = IconSpacingX;
  263.   int count = 0;
  264.  
  265.   while (x + gridWidth <= GetClientRect().Width()) {
  266.     count++;
  267.     x += gridWidth + IconSpacingX;
  268.   }
  269.   return count;
  270. }
  271.  
  272. void TShellWindow::OpenExec()
  273. {
  274.   TShellItem item = *CONST_CAST(TShellItem*, &(*ItemGrids)[SelectedItem].Item);
  275.  
  276.   // if we're working with a shortcut to a folder, switch to underlying if it's a folder
  277.   if (item.IsShortcut()) {
  278.     TShellItem resolvedItem = item.ResolveShortcut(*this);
  279.     if (resolvedItem.IsFolder())
  280.       item = resolvedItem;
  281.   }
  282.   if (item.IsFolder() || item.ContainsSubFolder())
  283.     TYPESAFE_DOWNCAST(GetApplication()->GetMainWindow()->GetClientWindow(), TShellMDIClient)->
  284.       MyFileNew(&item);
  285.   else {
  286.     HINSTANCE inst = ShellExecute(0, 0, item.GetDisplayName(TShellItem::ForParsing),
  287.                                   0, 0, SW_SHOWDEFAULT);
  288.     if ((int)inst <= 32)
  289.       // Houston, we have a problem
  290.       DisplayShellExecuteError((int)inst, item.GetDisplayName(TShellItem::ForParsing));
  291.   }
  292. }
  293.  
  294. void TShellWindow::DisplayShellExecuteError(int error, const char* itemName)
  295. {
  296.   char msg[256];
  297.   switch (error) {
  298.     case 0:
  299.       ::strcpy(msg, "The system is out of memory or resources.");
  300.       break;
  301.     case ERROR_FILE_NOT_FOUND:
  302.       ::strcpy(msg, "The specified file was not found.");
  303.       break;
  304.     case ERROR_PATH_NOT_FOUND:
  305.       ::strcpy(msg, "The specified path was not found.");
  306.       break;
  307.     case ERROR_BAD_FORMAT:
  308.       ::strcpy(msg, "The .EXE file is invalid (non-Win32 .EXE or error "
  309.                "in .EXE image).");
  310.       break;
  311.     case SE_ERR_ASSOCINCOMPLETE:
  312.       ::strcpy(msg, "The filename association is incomplete or invalid.");
  313.       break;
  314.     case SE_ERR_DDEBUSY:
  315.       ::strcpy(msg, "The DDE transaction could not be completed because "
  316.                "other DDE transactions were being processed.");
  317.       break;
  318.     case SE_ERR_DDEFAIL:
  319.       ::strcpy(msg, "The DDE transaction failed.");
  320.       break;
  321.     case SE_ERR_DDETIMEOUT:
  322.       ::strcpy(msg, "The DDE transaction could not be completed because "
  323.                "the request timed out.");
  324.       break;
  325.     case SE_ERR_NOASSOC:
  326.       ::strcpy(msg, "This file does not have a program associated with it "
  327.                "for performing this action.  Create an association in "
  328.                "My Computer by clicking View and then clicking Options.");
  329.       break;
  330.     case SE_ERR_SHARE:
  331.       ::strcpy(msg, "A sharing violation occurred.");
  332.       break;
  333.     default:
  334.       ::strcpy(msg, "Unkown error return code.");
  335.   }
  336.   // !JK MB_ICONERROR is >= Windows 4.0 only, if this causes a build problem
  337.   //     change MB_ICONERROR to MB_ICONHAND
  338.   MessageBox(msg, itemName, MB_OK | MB_ICONERROR);
  339. }
  340.  
  341. int TShellWindow::EvCreate(CREATESTRUCT far &cs)
  342. {
  343.   GetParentO()->SetCaption(Folder.GetDisplayName());
  344.   TYPESAFE_DOWNCAST(GetParentO(), TShellMDIChild)->SetIcon(Folder.GetIcon());
  345.   TYPESAFE_DOWNCAST(GetParentO(), TShellMDIChild)->SetIconSm(Folder.GetIcon(TShellItem::Small));
  346.   return TWindow::EvCreate(cs);
  347. }
  348.  
  349. void TShellWindow::EvGetMinMaxInfo(MINMAXINFO far& minmaxinfo)
  350. {
  351.   TWindow::EvGetMinMaxInfo(minmaxinfo);
  352. }
  353.  
  354. void TShellWindow::EvSize(uint sizeType, TSize& size)
  355. {
  356.   if (ClientRectWidth != GetClientRect().Width()) {
  357.     if (!ClientRectWidth || ItemsPerRow != ComputeItemsPerRow()) {
  358.       ItemsPerRow = ComputeItemsPerRow();
  359.       Invalidate();
  360.     }
  361.   }
  362.   TWindow::EvSize(sizeType, size);
  363. }
  364.  
  365. void TShellWindow::EvLButtonUp(uint /*modKeys*/, TPoint& point)
  366. {
  367.   int cnt = 0;
  368.   for (TArrayIterator<ItemGrid> i(*ItemGrids); i; i++, cnt++) {
  369.     if (i.Current().Grid.Contains(point)) {
  370.       TShellItem item = *CONST_CAST(TShellItem*, &i.Current().Item);
  371.       if (SelectedItem != cnt) {
  372.         if (SelectedItem != -1)
  373.           InvalidateRect((*ItemGrids)[SelectedItem].Grid);
  374.         SelectedItem = cnt;
  375.         InvalidateRect((*ItemGrids)[SelectedItem].Grid);
  376.       }
  377.       return;
  378.     }
  379.   }
  380.   if (SelectedItem != -1) {
  381.     InvalidateRect((*ItemGrids)[SelectedItem].Grid);
  382.     SelectedItem = -1;
  383.   }
  384. }
  385.  
  386. void TShellWindow::EvRButtonUp(uint /*modKeys*/, TPoint& point)
  387. {
  388.   int cnt = 0;
  389.   for (TArrayIterator<ItemGrid> i(*ItemGrids); i; i++, cnt++) {
  390.     if (i.Current().Grid.Contains(point)) {
  391.       TShellItem item = *CONST_CAST(TShellItem*, &i.Current().Item);
  392.       if (SelectedItem != cnt) {
  393.         if (SelectedItem != -1)
  394.           InvalidateRect((*ItemGrids)[SelectedItem].Grid);
  395.         SelectedItem = cnt;
  396.         InvalidateRect((*ItemGrids)[SelectedItem].Grid);
  397.       }
  398.       DisplayProperties(item);
  399.       return;
  400.     }
  401.   }
  402.   if (SelectedItem != -1) {
  403.     InvalidateRect((*ItemGrids)[SelectedItem].Grid);
  404.     SelectedItem = -1;
  405.   }
  406.   DisplayProperties(Folder);
  407. }
  408.  
  409. void TShellWindow::EvLButtonDblClk(uint /*modKeys*/, TPoint& /*point*/)
  410. {
  411.   if (SelectedItem != -1)
  412.     OpenExec();
  413. }
  414.  
  415. void TShellWindow::EvChar(uint key, uint repeatCount, uint flags)
  416. {
  417.   if (key == ' ' || key == '\r') {
  418.     if (SelectedItem != -1)
  419.       OpenExec();
  420.     }
  421.   else
  422.     TWindow::EvChar(key, repeatCount, flags);
  423. }
  424.  
  425.