Logo Search packages:      
Sourcecode: sarien version File versions  Download package

browse.cpp

// BROWSE.CPP - Simple file browser for Windows CE-based systems.
// Programmed by Vasyl Tsvirkunov.
//
#include <windows.h>
#include <commctrl.h>
// In case of HPC Pro you may have to copy this file from PocketPC devkit.
#include <aygshell.h>

#include "browse.h"

#define MENU_HEIGHT 26

// aygshell.dll is not present in some cases (HPC Pro). So, here's standard dynamic loading trick.

typedef BOOL tSHInitDialog(PSHINITDLGINFO);
typedef BOOL tSHInitExtraControls(void);
typedef WINSHELLAPI BOOL tSHHandleWMActivate(HWND hwnd, WPARAM wParam, LPARAM lParam, SHACTIVATEINFO* psai, DWORD dwFlags);
typedef WINSHELLAPI BOOL tSHHandleWMSettingChange(HWND hwnd, WPARAM wParam, LPARAM lParam, SHACTIVATEINFO* psai);

static tSHInitDialog* pSHInitDialog = NULL;
static tSHInitExtraControls* pSHInitExtraControls = NULL;
static tSHHandleWMActivate* pSHHandleWMActivate = NULL;
static tSHHandleWMSettingChange* pSHHandleWMSettingChange = NULL;

//

class cFileBrowserView
{
public:
      cFileBrowserView(BROWSEFILES* pbf);
      virtual ~cFileBrowserView();

protected:
      void InitView(HWND hwndDlg);
      void UpdateView(HWND hwndDlg, BOOL bChangePath);
      void UpdateLayout(HWND hwndDlg);
      void VerifyPath();

      void BrowserUp(HWND hwndDlg, int depth);
      void BrowserDown(HWND hwndDlg, LPTSTR item);

      void BrowseResult(HWND hwndDlg);

public:
      static BOOL CALLBACK BrowseDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);

protected:
      TCHAR currentFolder[MAX_PATH+1];
      SHACTIVATEINFO sai;
      
      int mnFolderImage;
      BROWSEFILES* mpbf;

      bool bInternalSelect;
};

#define CONTROL_GAP 10
#define LINE_HEIGHT 20


cFileBrowserView::cFileBrowserView(BROWSEFILES* pbf) : mpbf(pbf), bInternalSelect(false)
{
      if(mpbf->szStartDir == NULL || mpbf->szStartDir[0] == 0)
            currentFolder[0] = 0;
      else
            wcsncpy(currentFolder, mpbf->szStartDir, MAX_PATH);
}

cFileBrowserView::~cFileBrowserView()
{
}

void cFileBrowserView::InitView(HWND hwndDlg)
{
      SetWindowText(hwndDlg, mpbf->szCaption);
      HWND hwndList = GetDlgItem(hwndDlg, 1000);
      HIMAGELIST hil = ImageList_LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(mpbf->nImageId), 16, 0, CLR_DEFAULT, IMAGE_BITMAP, 0);
      ListView_SetImageList(hwndList, hil, LVSIL_SMALL);
      if(mpbf->dwFlags & BF_SELECTEXISTING)
      {
            HWND hwndEdit = GetDlgItem(hwndDlg, 1002);
            SendMessage(hwndEdit, EM_SETREADONLY, 1, 0);
      }
      for(int i=0;; i++)
      {
            if(mpbf->pExtImages[i].pExt == NULL)
            {
                  mnFolderImage = mpbf->pExtImages[i].nImageIndex;
                  break;
            }
      }
}

void cFileBrowserView::UpdateLayout(HWND hwndDlg)
{
      HWND hwndList = GetDlgItem(hwndDlg, 1000);
      HWND hwndCombo = GetDlgItem(hwndDlg, 1001);
      HWND hwndEdit = GetDlgItem(hwndDlg, 1002);
      HWND hwndOK = GetDlgItem(hwndDlg, IDOK);
      HWND hwndCancel = GetDlgItem(hwndDlg, IDCANCEL);

      RECT rc;
      GetClientRect(hwndDlg, &rc);
      int width = rc.right - rc.left;
      int height = rc.bottom - rc.top;

      int itemWidth = width-2*CONTROL_GAP;
      int buttonWidth = (width-3*CONTROL_GAP)/2;
      MoveWindow(hwndCombo, CONTROL_GAP, CONTROL_GAP, itemWidth, LINE_HEIGHT, TRUE);
      MoveWindow(hwndList, CONTROL_GAP, 2*CONTROL_GAP+LINE_HEIGHT, itemWidth, height-5*CONTROL_GAP-3*LINE_HEIGHT, TRUE);
      MoveWindow(hwndEdit, CONTROL_GAP, height-2*CONTROL_GAP-2*LINE_HEIGHT, itemWidth, LINE_HEIGHT, TRUE);
      MoveWindow(hwndOK, CONTROL_GAP, height-CONTROL_GAP-LINE_HEIGHT, buttonWidth, LINE_HEIGHT, TRUE);
      MoveWindow(hwndCancel, width-CONTROL_GAP-buttonWidth, height-CONTROL_GAP-LINE_HEIGHT, buttonWidth, LINE_HEIGHT, TRUE);
}

void cFileBrowserView::VerifyPath()
{
// Relative path is prepended with cwd. Path must be terminated with backslash
      if(currentFolder[0] == '.')
            currentFolder[0] = 0;

      if(currentFolder[0] != '\\')
      {
            TCHAR cwd[MAX_PATH];
            if(GetModuleFileName(GetModuleHandle(NULL), cwd, MAX_PATH))
            {
                  TCHAR* lastdir = wcsrchr(cwd, '\\');
                  if(lastdir)
                        *(lastdir+1) = 0;
                  wcscat(cwd, currentFolder);
                  wcscpy(currentFolder, cwd);
            }
      }

      if(currentFolder[0] != '\\') // There was some (generally bad) error
      {
            currentFolder[0] = '\\';
            currentFolder[1] = 0;
      }

// At this point currentFolder contains absolute folder path terminated with backslash.
// Verify path existence. If it does not exist, backstep.
      TCHAR verifyPath[MAX_PATH];
      wcscpy(verifyPath, currentFolder);

      while(1)
      {
            TCHAR* lastdir = wcsrchr(verifyPath, '\\');
            if(lastdir)
                  *lastdir = 0;
            if(verifyPath[0] == 0) // reached root?
                  break;
            DWORD attribs = GetFileAttributes(verifyPath);
            if(attribs & FILE_ATTRIBUTE_DIRECTORY) // valid directory?
                  break;
      }

// Re-terminate currentPath after backslash
      currentFolder[wcslen(verifyPath)+1] = 0;
}

void cFileBrowserView::UpdateView(HWND hwndDlg, BOOL bChangePath)
{
      HWND hwndList = GetDlgItem(hwndDlg, 1000);
      HWND hwndCombo = GetDlgItem(hwndDlg, 1001);
      HWND hwndEdit = GetDlgItem(hwndDlg, 1002);
      HWND hwndOK = GetDlgItem(hwndDlg, IDOK);

      if(bChangePath)
      {
            VerifyPath();

      // Fill combo box with items
            int depth = 0;
            TCHAR subfolder[MAX_PATH+3*16] = TEXT("My Device");
            SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
            SendMessage(hwndCombo, CB_INSERTSTRING, depth, (LPARAM)subfolder);

            TCHAR* ptr = currentFolder;
            TCHAR* nextptr = currentFolder;
            while(1)
            {
                  ptr = nextptr;
                  ptr ++;
                  if(*ptr == 0)
                        break;
                  nextptr = wcschr(ptr, '\\');
                  depth++;
                  subfolder[0] = 0;
                  for(int i=0; i<depth; i++)
                        wcscat(subfolder, TEXT("   "));
                  wcsncat(subfolder, ptr, nextptr-ptr);
                  SendMessage(hwndCombo, CB_INSERTSTRING, depth, (LPARAM)subfolder);
            }
            SendMessage(hwndCombo, CB_SETCURSEL, depth, 0);

      // Fill list box with items
            ListView_DeleteAllItems(hwndList);

            int index = 0;

      // For non-root folders -- add UP item
            if(wcslen(currentFolder) > 1)
            {
                  LVITEM lvi;
                  lvi.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
                  lvi.iItem = index++;
                  lvi.iSubItem = 0;
                  lvi.state = 0;
                  lvi.stateMask = 0;
                  lvi.pszText = TEXT("..");
                  lvi.cchTextMax = 0;
                  lvi.iImage = mnFolderImage;
                  lvi.lParam = -1;
                  lvi.iIndent = 0;
                  ListView_InsertItem(hwndList, &lvi);
            }

            TCHAR mask[MAX_PATH];
            wcscpy(mask, currentFolder);
            wcscat(mask, TEXT("*.*"));

            WIN32_FIND_DATA wfd;
            HANDLE hfind;
      // Directories first
            hfind = FindFirstFile(mask, &wfd);
            if(hfind != INVALID_HANDLE_VALUE)
            {
                  while(1)
                  {
                        if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                        {
                              LVITEM lvi;
                              lvi.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
                              lvi.iItem = index++;
                              lvi.iSubItem = 0;
                              lvi.state = 0;
                              lvi.stateMask = 0;
                              lvi.pszText = wfd.cFileName;
                              lvi.cchTextMax = 0;
                              lvi.iImage = mnFolderImage;
                              lvi.lParam = -1;
                              lvi.iIndent = 0;
                              ListView_InsertItem(hwndList, &lvi);
                        }

                        if(!FindNextFile(hfind, &wfd))
                              break;
                  }
                  FindClose(hfind);
            }

      // Then masked files
            for(int ext=0; mpbf->pExtImages[ext].pExt; ext++)
            {
                  wcscpy(mask, currentFolder);
                  wcscat(mask, TEXT("*."));
                  wcscat(mask, mpbf->pExtImages[ext].pExt);
                  int iImage = mpbf->pExtImages[ext].nImageIndex;

                  hfind = FindFirstFile(mask, &wfd);
                  if(hfind != INVALID_HANDLE_VALUE)
                  {
                        while(1)
                        {
                              if(!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
                              {
                                    LVITEM lvi;
                                    lvi.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
                                    lvi.iItem = index++;
                                    lvi.iSubItem = 0;
                                    lvi.state = 0;
                                    lvi.stateMask = 0;
                                    lvi.pszText = wfd.cFileName;
                                    lvi.cchTextMax = 0;
                                    lvi.iImage = iImage;
                                    lvi.lParam = 0;
                                    lvi.iIndent = 0;
                                    ListView_InsertItem(hwndList, &lvi);
                              }

                              if(!FindNextFile(hfind, &wfd))
                                    break;
                        }
                        FindClose(hfind);
                  }
            }

      // NEED TO SORT ITEMS HERE!
      }

      EnableWindow(hwndOK, FALSE);  

      TCHAR string[MAX_PATH];
      GetWindowText(hwndEdit, string, MAX_PATH);
      bInternalSelect = true;
      if(string[0])
      {
            LV_FINDINFO lvf;
            lvf.flags = LVFI_STRING;
            lvf.psz = string;
            int item = ListView_FindItem(hwndList, 0, &lvf);
            if(item != -1)
            {
                  ListView_SetItemState(hwndList, item, LVIS_SELECTED, LVIS_SELECTED);
                  ListView_EnsureVisible(hwndList, item, FALSE);
            }
            EnableWindow(hwndOK, TRUE);   
      }
      else
      {
            ListView_SetItemState(hwndList, 0, LVIS_SELECTED, LVIS_SELECTED);
            ListView_EnsureVisible(hwndList, 0, FALSE);
      }
      bInternalSelect = false;
}

void cFileBrowserView::BrowserUp(HWND hwndDlg, int depth)
{
      TCHAR* ptr = currentFolder;
      for(int i=0; i<depth+1; i++)
      {
            ptr = wcschr(ptr, '\\');
            if(ptr)
                  ptr++;
            else
                  break;
      }
      if(ptr)
            *ptr = 0;

      SetWindowText(GetDlgItem(hwndDlg, 1002), TEXT(""));
      UpdateView(hwndDlg, TRUE);
}

void cFileBrowserView::BrowserDown(HWND hwndDlg, LPTSTR item)
{
      if(wcslen(currentFolder) <= 1 || wcscmp(TEXT(".."), item) != 0)
      {
            TCHAR fullpath[MAX_PATH];
            wcscpy(fullpath, currentFolder);
            wcscat(fullpath, item);

            DWORD attribs = GetFileAttributes(fullpath);
            if(attribs & FILE_ATTRIBUTE_DIRECTORY)
            {
                  wcscpy(currentFolder, fullpath);
                  wcscat(currentFolder, TEXT("\\"));

                  SetWindowText(GetDlgItem(hwndDlg, 1002), TEXT(""));
                  UpdateView(hwndDlg, TRUE);
            }
            else
            {
                  SetWindowText(GetDlgItem(hwndDlg, 1002), item);
                  UpdateView(hwndDlg, FALSE);
            }
      }
      else
      {
            TCHAR* pclose = wcsrchr(currentFolder, '\\');
            if(pclose && pclose != currentFolder) // sanity check
            {
                  *pclose = 0;
                  pclose = wcsrchr(currentFolder, '\\');
                  pclose++;
                  *pclose = 0;

                  SetWindowText(GetDlgItem(hwndDlg, 1002), TEXT(""));
                  UpdateView(hwndDlg, TRUE);
            }
      }
}

void cFileBrowserView::BrowseResult(HWND hwndDlg)
{
      TCHAR strName[MAX_PATH];
      GetWindowText(GetDlgItem(hwndDlg, 1002), strName, MAX_PATH);

      if(!wcschr(strName, '.') && mpbf->szDefExt)
      {
            wcsncat(strName, TEXT("."), MAX_PATH-wcslen(strName));
            wcsncat(strName, mpbf->szDefExt, MAX_PATH-wcslen(strName));
      }
      if(mpbf->pBuffer && mpbf->nBufSize)
      {
            wcsncpy(mpbf->pBuffer, currentFolder, mpbf->nBufSize);
            wcsncat(mpbf->pBuffer, strName, mpbf->nBufSize - wcslen(mpbf->pBuffer));
      }
      if(mpbf->pBufferShort && mpbf->nBufShortSize)
      {
            TCHAR* pdot = wcsrchr(strName, '.');
            if(pdot)
                  *pdot = 0;
            wcsncpy(mpbf->pBufferShort, strName, mpbf->nBufShortSize);
      }
}


BOOL CALLBACK cFileBrowserView::BrowseDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
      cFileBrowserView* pView = (cFileBrowserView*)GetWindowLong(hwndDlg, DWL_USER);

      switch(uMsg)
      {
      case WM_INITDIALOG:
            {
                  SetWindowLong(hwndDlg, DWL_USER, lParam);
                  pView = (cFileBrowserView*)lParam;

                  memset(&pView->sai, 0, sizeof(SHACTIVATEINFO));

                  SHINITDLGINFO shidi;
                  shidi.dwMask = SHIDIM_FLAGS;
                  shidi.dwFlags = SHIDIF_SIPDOWN | SHIDIF_SIZEDLG;
                  shidi.hDlg = hwndDlg;
                  if(pSHInitDialog)
                        pSHInitDialog(&shidi);

                  pView->InitView(hwndDlg);
                  pView->UpdateView(hwndDlg, TRUE);
            }
            return TRUE;

      case WM_ACTIVATE:
            if(pSHHandleWMActivate)
                  pSHHandleWMActivate(hwndDlg, wParam, lParam, &pView->sai, 0);
            return TRUE;

      case WM_SETTINGCHANGE:
            // 'dirtree' example differs from documentation but this one works
            if(pSHHandleWMSettingChange)
                  pSHHandleWMSettingChange(hwndDlg, -1, 0, &pView->sai);
            return TRUE;

      case WM_SIZE:
            pView->UpdateLayout(hwndDlg);
            return TRUE;

      case WM_NOTIFY:
            {
                  if(!pView->bInternalSelect)
                  {
                        LPNMHDR nmhdr = (LPNMHDR)lParam;
                        HWND hwndList = GetDlgItem(hwndDlg, 1000);
                        if(nmhdr->hwndFrom == hwndList && nmhdr->code == LVN_ITEMCHANGED)
                        {
                              LPNMLISTVIEW lplv = (LPNMLISTVIEW)lParam;
                              if(lplv && (lplv->uNewState & LVIS_SELECTED))
                              {
                                    int item = lplv->iItem;
                                    TCHAR itemText[MAX_PATH];
                                    ListView_GetItemText(hwndList, item, 0, itemText, MAX_PATH);
                                    pView->BrowserDown(hwndDlg, itemText);
                                    return TRUE;
                              }
                        }
                  }
            }
            return FALSE;

      case WM_COMMAND:
            if(HIWORD(wParam)) // notification
            {
                  if(HIWORD(wParam) == CBN_SELCHANGE)
                  {
                        HWND hwndCombo = GetDlgItem(hwndDlg, 1001);
                        if((HWND)lParam == hwndCombo)
                        {
                              int item = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
                              pView->BrowserUp(hwndDlg, item);
                              return TRUE;
                        }
                  }
            }
            else
            {
                  switch(wParam)
                  {
                  case IDOK:
                        pView->BrowseResult(hwndDlg);
                        EndDialog(hwndDlg, 1);
                        return TRUE;
                  case IDCANCEL:
                        EndDialog(hwndDlg, 0);
                        return TRUE;
                  }
            }
      default:
            return FALSE;
      }
}



bool BrowseFiles(BROWSEFILES* pbf)
{
      HMODULE hShell = LoadLibrary(TEXT("aygshell.dll"));
      if(hShell != NULL)
      {
            pSHInitDialog = (tSHInitDialog*)GetProcAddress(hShell, TEXT("SHInitDialog"));
            pSHInitExtraControls = (tSHInitExtraControls*)GetProcAddress(hShell, TEXT("SHInitExtraControls"));
            pSHHandleWMActivate = (tSHHandleWMActivate*)GetProcAddress(hShell, TEXT("SHHandleWMActivate"));
            pSHHandleWMSettingChange = (tSHHandleWMSettingChange*)GetProcAddress(hShell, TEXT("SHHandleWMSettingChange"));
      }

      if(!pbf)
            return false;
      if(!pbf->pBuffer || pbf->nBufSize == 0)
            return false;
      if(!pbf->pExtImages)
            return false;

      if(pSHInitExtraControls)
            pSHInitExtraControls(); // Required to use WC_SIPPREF control

      cFileBrowserView* pView = new cFileBrowserView(pbf);
      bool bResult = DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(pbf->nTemplateId), NULL, cFileBrowserView::BrowseDlgProc, (LPARAM)pView) == IDOK;
      delete pView; pView = NULL;
      return bResult;
}

Generated by  Doxygen 1.6.0   Back to index