]> cygwin.com Git - cygwin-apps/setup.git/blobdiff - ListView.cc
Suppress bogus free-nonheap-object warning in iniparse.cc
[cygwin-apps/setup.git] / ListView.cc
index e80774144e266a1426d4c1d07064e473cad8cfa4..62a37ab173b6bf0bec3a130378425c3dd6e667fb 100644 (file)
@@ -14,6 +14,7 @@
 #include "ListView.h"
 #include "LogSingleton.h"
 #include "resource.h"
+#include "String++.h"
 
 #include <commctrl.h>
 
@@ -95,6 +96,9 @@ ListView::init(HWND parent, int id, HeaderList headers)
   SendMessage(hWndTip, TTM_SETDELAYTIME, TTDT_AUTOPOP, (LPARAM) MAKELONG (30000, 0));
   // match tip width used elsewhere
   SendMessage(hWndTip, TTM_SETMAXTIPWIDTH, 0, 450);
+
+  // switch to using wide-char WM_NOTIFY messages
+  ListView_SetUnicodeFormat(hWndListView, TRUE);
 }
 
 void
@@ -104,18 +108,20 @@ ListView::initColumns(HeaderList headers_)
   headers = headers_;
 
   // create the columns
-  LVCOLUMN lvc;
+  LVCOLUMNW lvc;
   lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
 
   int i;
   for (i = 0; headers[i].text != 0; i++)
     {
+      std::wstring h = LoadStringW(headers[i].text);
+
       lvc.iSubItem = i;
-      lvc.pszText = const_cast <char *> (headers[i].text);
+      lvc.pszText = const_cast <wchar_t *> (h.c_str());
       lvc.cx = 100;
       lvc.fmt = headers[i].fmt;
 
-      ListView_InsertColumn(hWndListView, i, &lvc);
+      SendMessage(hWndListView, LVM_INSERTCOLUMNW, i, (LPARAM)&lvc);
     }
 
   // now do some width calculations
@@ -145,8 +151,23 @@ ListView::noteColumnWidthStart()
     }
 }
 
+// wrappers to help instantiations of the noteColumnWidth() template call the
+// right version of GetTextExtentPoint32
+#undef GetTextExtentPoint32
+
+static BOOL GetTextExtentPoint32(HDC hdc, LPCSTR lpString, int c, LPSIZE psizl)
+{
+  return GetTextExtentPoint32A(hdc, lpString, c, psizl);
+}
+
+static BOOL GetTextExtentPoint32(HDC hdc, LPCWSTR lpString, int c, LPSIZE psizl)
+{
+  return GetTextExtentPoint32W(hdc, lpString, c, psizl);
+}
+
+template <typename T>
 void
-ListView::noteColumnWidth(int col_num, const std::string& string)
+ListView::noteColumnWidth(int col_num, const T& string)
 {
   SIZE s = { 0, 0 };
 
@@ -169,6 +190,10 @@ ListView::noteColumnWidth(int col_num, const std::string& string)
     headers[col_num].width = width;
 }
 
+// explicit instantiation
+template void ListView::noteColumnWidth(int col_num, const std::string& string);
+template void ListView::noteColumnWidth(int col_num, const std::wstring& wstring);
+
 void
 ListView::noteColumnWidthEnd()
 {
@@ -256,29 +281,30 @@ ListView::setContents(ListViewContents *_contents, bool tree)
   RedrawWindow(hWndListView, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
 }
 
-// Helper class: The char * pointer we hand back needs to remain valid for some
-// time after OnNotify returns, when the std::string we have retrieved has gone
-// out of scope, so a static instance of this class maintains a local cache.
-class StringCache
+// Helper class: The pointer we hand back needs to remain valid for some time
+// after OnNotify returns, when the string object we have retrieved has gone out
+// of scope, so a static instance of this class maintains a local cache.
+template <class T> class StringCache
 {
+  typedef typename T::traits_type::char_type char_type;
 public:
   StringCache() : cache(NULL), cache_size(0) { }
-  StringCache & operator = (const std::string & s)
+  StringCache & operator = (const T & s)
   {
     if ((s.length() + 1) > cache_size)
       {
         cache_size = s.length() + 1;
-        cache = (char *)realloc(cache, cache_size);
+        cache = (char_type *)realloc(cache, cache_size * sizeof(char_type));
       }
-    strcpy(cache, s.c_str());
+    memcpy(cache, s.c_str(), (s.length() + 1) * sizeof(char_type));
     return *this;
   }
-  operator char *() const
+  operator char_type *() const
   {
     return cache;
   }
 private:
-  char *cache;
+  char_type *cache;
   size_t cache_size;
 };
 
@@ -291,9 +317,9 @@ ListView::OnNotify (NMHDR *pNmHdr, LRESULT *pResult)
 
   switch (pNmHdr->code)
   {
-  case LVN_GETDISPINFO:
+  case LVN_GETDISPINFOW:
     {
-      NMLVDISPINFO *pNmLvDispInfo = (NMLVDISPINFO *)pNmHdr;
+      NMLVDISPINFOW *pNmLvDispInfo = (NMLVDISPINFOW *)pNmHdr;
 #if DEBUG
       Log (LOG_BABBLE) << "LVN_GETDISPINFO " << pNmLvDispInfo->item.iItem << endLog;
 #endif
@@ -302,7 +328,7 @@ ListView::OnNotify (NMHDR *pNmHdr, LRESULT *pResult)
           int iRow = pNmLvDispInfo->item.iItem;
           int iCol = pNmLvDispInfo->item.iSubItem;
 
-          static StringCache s;
+          static StringCache<std::wstring> s;
           s = (*contents)[iRow]->get_text(iCol);
           pNmLvDispInfo->item.pszText = s;
 
@@ -319,11 +345,7 @@ ListView::OnNotify (NMHDR *pNmHdr, LRESULT *pResult)
   case LVN_GETEMPTYMARKUP:
     {
       NMLVEMPTYMARKUP *pNmMarkup = (NMLVEMPTYMARKUP*) pNmHdr;
-
-      MultiByteToWideChar(CP_UTF8, 0,
-                          empty_list_text, -1,
-                          pNmMarkup->szMarkup, L_MAX_URL_LENGTH);
-
+      wcsncpy(pNmMarkup->szMarkup, empty_list_text.c_str(), L_MAX_URL_LENGTH);
       *pResult = true;
       return true;
     }
@@ -345,9 +367,19 @@ ListView::OnNotify (NMHDR *pNmHdr, LRESULT *pResult)
       if (headers[iCol].type == ListView::ControlType::popup)
         {
           POINT p;
-          // position pop-up menu at the location of the click
           GetCursorPos(&p);
 
+          RECT r;
+          ListView_GetSubItemRect(hWndListView, iRow, iCol, LVIR_BOUNDS, &r);
+          POINT cp = p;
+          ::ScreenToClient(hWndListView, &cp);
+
+          // if the click isn't over the pop-up button, do nothing yet (but this
+          // might be followed by a NM_DBLCLK)
+          if (cp.x < r.right - GetSystemMetrics(SM_CXVSCROLL))
+            return true;
+
+          // position pop-up menu at the location of the click
           update = popup_menu(iRow, iCol, p);
         }
       else
@@ -366,6 +398,32 @@ ListView::OnNotify (NMHDR *pNmHdr, LRESULT *pResult)
     }
     break;
 
+  case NM_DBLCLK:
+    {
+      NMITEMACTIVATE *pNmItemAct = (NMITEMACTIVATE *) pNmHdr;
+#if DEBUG
+      Log (LOG_BABBLE) << "NM_DBLCLICK: pnmitem->iItem " << pNmItemAct->iItem << " pNmItemAct->iSubItem " << pNmItemAct->iSubItem << endLog;
+#endif
+      int iRow = pNmItemAct->iItem;
+      int iCol = pNmItemAct->iSubItem;
+      if (iRow < 0)
+        return false;
+
+      int update = 0;
+
+      // Inform the item of the double-click
+      update = (*contents)[iRow]->do_default_action(iCol );
+
+      // Update items, if needed
+      if (update > 0)
+        {
+          ListView_RedrawItems(hWndListView, iRow, iRow + update -1);
+        }
+
+      return true;
+    }
+    break;
+
   case NM_CUSTOMDRAW:
     {
       NMLVCUSTOMDRAW *pNmLvCustomDraw = (NMLVCUSTOMDRAW *)pNmHdr;
@@ -393,7 +451,7 @@ ListView::OnNotify (NMHDR *pNmHdr, LRESULT *pResult)
 
               case ListView::ControlType::checkbox:
                 {
-                  // get the subitem text
+                  // get the subitem text (as ASCII)
                   char buf[3];
                   ListView_GetItemText(hWndListView, iRow, iCol, buf, _countof(buf));
 
@@ -501,6 +559,42 @@ ListView::OnNotify (NMHDR *pNmHdr, LRESULT *pResult)
     }
     break;
 
+  case LVN_KEYDOWN:
+    {
+      NMLVKEYDOWN *pNmLvKeyDown = (NMLVKEYDOWN *)pNmHdr;
+      int iRow = ListView_GetSelectionMark(hWndListView);
+#if DEBUG
+      Log (LOG_PLAIN) << "LVN_KEYDOWN vkey " << pNmLvKeyDown->wVKey << " on row " << iRow << endLog;
+#endif
+
+      if (contents && iRow >= 0)
+        {
+          int col_num;
+          int action_id;
+          if ((*contents)[iRow]->map_key_to_action(pNmLvKeyDown->wVKey, &col_num, &action_id))
+            {
+              int update;
+              if (action_id >= 0)
+                update = (*contents)[iRow]->do_action(col_num, action_id);
+              else
+                {
+                  POINT p;
+                  RECT r;
+                  ListView_GetSubItemRect(hWndListView, iRow, col_num, LVIR_BOUNDS, &r);
+                  p.x = r.left;
+                  p.y = r.top;
+                  ClientToScreen(hWndListView, &p);
+
+                  update = popup_menu(iRow, col_num, p);
+                }
+
+              if (update > 0)
+                ListView_RedrawItems(hWndListView, iRow, iRow + update -1);
+            }
+        }
+    }
+    break;
+
   case TTN_GETDISPINFO:
     {
       // convert mouse position to item/subitem
@@ -520,7 +614,7 @@ ListView::OnNotify (NMHDR *pNmHdr, LRESULT *pResult)
 #endif
 
       // get the tooltip text for that item/subitem
-      static StringCache tooltip;
+      static StringCache<std::string> tooltip;
       tooltip = "";
       if (contents)
         tooltip = (*contents)[iRow]->get_tooltip(iCol);
@@ -547,9 +641,9 @@ ListView::empty(void)
 }
 
 void
-ListView::setEmptyText(const char *text)
+ListView::setEmptyText(unsigned int text)
 {
-  empty_list_text = text;
+  empty_list_text = LoadStringW(text);
 }
 
 int
@@ -559,7 +653,7 @@ ListView::popup_menu(int iRow, int iCol, POINT p)
   // construct menu
   HMENU hMenu = CreatePopupMenu();
 
-  MENUITEMINFO mii;
+  MENUITEMINFOW mii;
   memset(&mii, 0, sizeof(mii));
   mii.cbSize = sizeof(mii);
   mii.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_STRING | MIIM_ID;
@@ -572,12 +666,12 @@ ListView::popup_menu(int iRow, int iCol, POINT p)
   for (i = al->list.begin (); i != al->list.end (); ++i, ++j)
     {
       BOOL res;
-      mii.dwTypeData = (char *)i->name.c_str();
+      mii.dwTypeData = const_cast <wchar_t *> (i->name.c_str());
       mii.fState = (i->selected ? MFS_CHECKED : MFS_UNCHECKED |
                     i->enabled ? MFS_ENABLED : MFS_DISABLED);
       mii.wID = j;
 
-      res = InsertMenuItem(hMenu, -1, TRUE, &mii);
+      res = InsertMenuItemW(hMenu, -1, TRUE, &mii);
       if (!res) Log (LOG_BABBLE) << "InsertMenuItem failed " << endLog;
     }
 
This page took 0.040451 seconds and 5 git commands to generate.