Logo Search packages:      
Sourcecode: filezilla version File versions

sitemanager.cpp

#include "FileZilla.h"
#include "sitemanager.h"
#include "Options.h"
#include "../tinyxml/tinyxml.h"
#include "xmlfunctions.h"
#include "filezillaapp.h"
#include "ipcmutex.h"
#include "wrapengine.h"

std::map<int, CSiteManagerItemData*> CSiteManager::m_idMap;

BEGIN_EVENT_TABLE(CSiteManager, wxDialogEx)
EVT_BUTTON(XRCID("wxID_OK"), CSiteManager::OnOK)
EVT_BUTTON(XRCID("wxID_CANCEL"), CSiteManager::OnCancel)
EVT_BUTTON(XRCID("ID_CONNECT"), CSiteManager::OnConnect)
EVT_BUTTON(XRCID("ID_NEWSITE"), CSiteManager::OnNewSite)
EVT_BUTTON(XRCID("ID_NEWFOLDER"), CSiteManager::OnNewFolder)
EVT_BUTTON(XRCID("ID_RENAME"), CSiteManager::OnRename)
EVT_BUTTON(XRCID("ID_DELETE"), CSiteManager::OnDelete)
EVT_TREE_BEGIN_LABEL_EDIT(XRCID("ID_SITETREE"), CSiteManager::OnBeginLabelEdit)
EVT_TREE_END_LABEL_EDIT(XRCID("ID_SITETREE"), CSiteManager::OnEndLabelEdit)
EVT_TREE_SEL_CHANGING(XRCID("ID_SITETREE"), CSiteManager::OnSelChanging)
EVT_TREE_SEL_CHANGED(XRCID("ID_SITETREE"), CSiteManager::OnSelChanged)
EVT_CHOICE(XRCID("ID_LOGONTYPE"), CSiteManager::OnLogontypeSelChanged)
EVT_BUTTON(XRCID("ID_BROWSE"), CSiteManager::OnRemoteDirBrowse)
EVT_TREE_ITEM_ACTIVATED(XRCID("ID_SITETREE"), CSiteManager::OnItemActivated)
EVT_CHECKBOX(XRCID("ID_LIMITMULTIPLE"), CSiteManager::OnLimitMultipleConnectionsChanged)
EVT_RADIOBUTTON(XRCID("ID_CHARSET_AUTO"), CSiteManager::OnCharsetChange)
EVT_RADIOBUTTON(XRCID("ID_CHARSET_UTF8"), CSiteManager::OnCharsetChange)
EVT_RADIOBUTTON(XRCID("ID_CHARSET_CUSTOM"), CSiteManager::OnCharsetChange)
EVT_CHOICE(XRCID("ID_PROTOCOL"), CSiteManager::OnProtocolSelChanged)
EVT_BUTTON(XRCID("ID_COPY"), CSiteManager::OnCopySite)
#ifdef __WXGTK__
EVT_SPINCTRL(-1, CSiteManager::OnTimezoneOffsetChanged)
#endif
END_EVENT_TABLE()

CSiteManager::CSiteManager()
{
      m_pSiteManagerMutex = 0;
#ifdef __WXGTK__
      m_timezoneOffsetHoursChanged;
      m_timezoneOffsetMinutesChanged;
      m_limitConnectionsChanged;
#endif
}

CSiteManager::~CSiteManager()
{
      delete m_pSiteManagerMutex;
}

bool CSiteManager::Create(wxWindow* parent)
{
      m_pSiteManagerMutex = new CInterProcessMutex(MUTEX_SITEMANAGERGLOBAL, false);
      if (!m_pSiteManagerMutex->TryLock())
      {
            int answer = wxMessageBox(_("The Site Manager is opened in another instance of FileZilla 3.\nDo you want to continue? Any changes made in the Site Manager won't be saved then."),
                                                  _("Site Manager already open"), wxYES_NO | wxICON_QUESTION);
            if (answer != wxYES)
                  return false;

            delete m_pSiteManagerMutex;
            m_pSiteManagerMutex = 0;
      }
      SetExtraStyle(wxWS_EX_BLOCK_EVENTS);
      SetParent(parent);
      CreateControls();

      // Now create the imagelist for the site tree
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return false;
      wxImageList* pImageList = new wxImageList(16, 16);

      pImageList->Add(wxArtProvider::GetBitmap(_T("ART_FOLDERCLOSED"),  wxART_OTHER, wxSize(16, 16)));
      pImageList->Add(wxArtProvider::GetBitmap(_T("ART_FOLDER"),  wxART_OTHER, wxSize(16, 16)));
      pImageList->Add(wxArtProvider::GetBitmap(_T("ART_SERVER"),  wxART_OTHER, wxSize(16, 16)));

      pTree->AssignImageList(pImageList);

      Layout();
      wxGetApp().GetWrapEngine()->WrapRecursive(this, 1.33, "Site Manager");

      wxSize minSize = GetSizer()->GetMinSize();

      wxSize size = GetSize();
      wxSize clientSize = GetClientSize();
      SetMinSize(GetSizer()->GetMinSize() + size - clientSize);
      SetClientSize(minSize);

      Load();

      XRCCTRL(*this, "ID_TRANSFERMODE_DEFAULT", wxRadioButton)->Update();
      XRCCTRL(*this, "ID_TRANSFERMODE_ACTIVE", wxRadioButton)->Update();
      XRCCTRL(*this, "ID_TRANSFERMODE_PASSIVE", wxRadioButton)->Update();

      SetCtrlState();

      return true;
}

void CSiteManager::CreateControls()
{
      wxXmlResource::Get()->LoadDialog(this, GetParent(), _T("ID_SITEMANAGER"));

      wxChoice *pProtocol = XRCCTRL(*this, "ID_PROTOCOL", wxChoice);
      pProtocol->Append(CServer::GetProtocolName(FTP));
      pProtocol->Append(CServer::GetProtocolName(SFTP));
      pProtocol->Append(CServer::GetProtocolName(FTPS));
      pProtocol->Append(CServer::GetProtocolName(FTPES));

      wxChoice *pChoice = XRCCTRL(*this, "ID_SERVERTYPE", wxChoice);
      wxASSERT(pChoice);
      pChoice->Append(_T("Unix"));
      pChoice->Append(_T("VMS"));
      pChoice->Append(_T("MVS"));
      pChoice->Append(_T("Dos"));
      pChoice->Append(_T("VxWorks"));
}

void CSiteManager::OnOK(wxCommandEvent& event)
{
      if (!Verify())
            return;

      UpdateServer();

      Save();

      EndModal(wxID_OK);
}

void CSiteManager::OnCancel(wxCommandEvent& event)
{
      EndModal(wxID_CANCEL);
}

void CSiteManager::OnConnect(wxCommandEvent& event)
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return;

      wxTreeItemId item = pTree->GetSelection();
      if (!item.IsOk())
            return;

      CSiteManagerItemData* data = reinterpret_cast<CSiteManagerItemData* >(pTree->GetItemData(item));
      if (!data)
      {
            wxBell();
            return;
      }

      if (!Verify())
      {
            wxBell();
            return;
      }

      UpdateServer();

      Save();

      EndModal(wxID_YES);
}

class CSiteManagerXmlHandler
{
public:
      virtual ~CSiteManagerXmlHandler() {};

      // Adds a folder and descents
      virtual bool AddFolder(const wxString& name) = 0;
      virtual bool AddSite(const wxString& name, CSiteManagerItemData* data) = 0;

      // Go up a level
      virtual bool LevelUp() = 0; // *Ding*
};

class CSiteManagerXmlHandler_Tree : public CSiteManagerXmlHandler
{
public:
      CSiteManagerXmlHandler_Tree(wxTreeCtrl* pTree, wxTreeItemId root)
            : m_pTree(pTree), m_item(root)
      {
      }

      virtual ~CSiteManagerXmlHandler_Tree()
      {
            m_pTree->SortChildren(m_item);
            m_pTree->Expand(m_item);
      }

      virtual bool AddFolder(const wxString& name)
      {
            wxTreeItemId newItem = m_pTree->AppendItem(m_item, name, 0, 0);
            m_pTree->SetItemImage(newItem, 1, wxTreeItemIcon_Expanded);
            m_pTree->SetItemImage(newItem, 1, wxTreeItemIcon_SelectedExpanded);

            m_item = newItem;

            return true;
      }

      virtual bool AddSite(const wxString& name, CSiteManagerItemData* data)
      {
            m_pTree->AppendItem(m_item, name, 2, 2, data);

            return true;
      }

      virtual bool LevelUp()
      {
            m_pTree->SortChildren(m_item);
            m_pTree->Expand(m_item);

            wxTreeItemId parent = m_pTree->GetItemParent(m_item);
            if (!parent)
                  return false;

            m_item = parent;
            return true;
      }

protected:
      wxTreeCtrl* m_pTree;
      wxTreeItemId m_item;
};

bool CSiteManager::Load()
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return false;

      pTree->DeleteAllItems();

      // We have to synchronize access to sitemanager.xml so that multiple processed don't write
      // to the same file or one is reading while the other one writes.
      CInterProcessMutex mutex(MUTEX_SITEMANAGER);

      // Load default sites
      bool hasDefaultSites = LoadDefaultSites();
      if (hasDefaultSites)
            m_ownSites = pTree->AppendItem(pTree->GetRootItem(), _("My Sites"), 0, 0);
      else
            m_ownSites = pTree->AddRoot(_("My Sites"), 0, 0);

      wxTreeItemId treeId = m_ownSites;
      pTree->SelectItem(treeId);
      pTree->SetItemImage(treeId, 1, wxTreeItemIcon_Expanded);
      pTree->SetItemImage(treeId, 1, wxTreeItemIcon_SelectedExpanded);

      CXmlFile file(_T("sitemanager"));
      TiXmlElement* pDocument = file.Load();
      if (!pDocument)
      {
            wxString msg = wxString::Format(_("Could not load \"%s\", please make sure the file is valid and can be accessed.\nAny changes made in the Site Manager will not be saved."), file.GetFileName().GetFullPath().c_str());
            wxMessageBox(msg, _("Error loading xml file"), wxICON_ERROR);

            return false;
      }

      TiXmlElement* pElement = pDocument->FirstChildElement("Servers");
      if (!pElement)
            return true;

      CSiteManagerXmlHandler_Tree handler(pTree, treeId);

      bool res = Load(pElement, &handler);

      pTree->SortChildren(treeId);
      pTree->Expand(treeId);
      pTree->SelectItem(treeId);

      return res;
}

bool CSiteManager::Load(TiXmlElement *pElement, CSiteManagerXmlHandler* pHandler)
{
      wxASSERT(pElement);
      wxASSERT(pHandler);

      for (TiXmlElement* pChild = pElement->FirstChildElement(); pChild; pChild = pChild->NextSiblingElement())
      {
            TiXmlNode* pNode = pChild->FirstChild();
            while (pNode && !pNode->ToText())
                  pNode = pNode->NextSibling();

            if (!pNode)
                  continue;

            wxString name = ConvLocal(pNode->ToText()->Value());

            if (!strcmp(pChild->Value(), "Folder"))
            {
                  if (!pHandler->AddFolder(name))
                        return false;
                  Load(pChild, pHandler);
                  if (!pHandler->LevelUp())
                        return false;
            }
            else if (!strcmp(pChild->Value(), "Server"))
            {
                  CSiteManagerItemData* data = ReadServerElement(pChild);

                  if (data)
                        pHandler->AddSite(name, data);
            }
      }

      return true;
}

CSiteManagerItemData* CSiteManager::ReadServerElement(TiXmlElement *pElement)
{
      CServer server;
      if (!::GetServer(pElement, server))
            return 0;

      CSiteManagerItemData* data = new CSiteManagerItemData(server);

      TiXmlHandle handle(pElement);

      TiXmlText* comments = handle.FirstChildElement("Comments").FirstChild().Text();
      if (comments)
            data->m_comments = ConvLocal(comments->Value());

      TiXmlText* localDir = handle.FirstChildElement("LocalDir").FirstChild().Text();
      if (localDir)
            data->m_localDir = ConvLocal(localDir->Value());

      TiXmlText* remoteDir = handle.FirstChildElement("RemoteDir").FirstChild().Text();
      if (remoteDir)
            data->m_remoteDir.SetSafePath(ConvLocal(remoteDir->Value()));

      return data;
}

bool CSiteManager::Save(TiXmlElement *pElement /*=0*/, wxTreeItemId treeId /*=wxTreeItemId()*/)
{
      if (!m_pSiteManagerMutex)
            return false;

      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return false;

      if (!pElement || !treeId)
      {
            // We have to synchronize access to sitemanager.xml so that multiple processed don't write
            // to the same file or one is reading while the other one writes.
            CInterProcessMutex mutex(MUTEX_SITEMANAGER);

            wxFileName file(wxGetApp().GetSettingsDir(), _T("sitemanager.xml"));
            TiXmlElement* pDocument = GetXmlFile(file);
            if (!pDocument)
            {
                  wxString msg = wxString::Format(_("Could not load \"%s\", please make sure the file is valid and can be accessed.\nAny changes made in the Site Manager could not be saved."), file.GetFullPath().c_str());
                  wxMessageBox(msg, _("Error loading xml file"), wxICON_ERROR);

                  return false;
            }

            TiXmlElement *pServers = pDocument->FirstChildElement("Servers");
            while (pServers)
            {
                  pDocument->RemoveChild(pServers);
                  pServers = pDocument->FirstChildElement("Servers");
            }
            pElement = pDocument->InsertEndChild(TiXmlElement("Servers"))->ToElement();

            if (!pElement)
            {
                  delete pDocument->GetDocument();

                  return true;
            }

            bool res = Save(pElement, m_ownSites);

            wxString error;
            if (!SaveXmlFile(file, pDocument, &error))
            {
                  wxString msg = wxString::Format(_("Could not write \"%s\", any changes to the Site Manager could not be saved: %s"), file.GetFullPath().c_str(), error.c_str());
                  wxMessageBox(msg, _("Error writing xml file"), wxICON_ERROR);
            }

            delete pDocument->GetDocument();
            return res;
      }

      wxTreeItemId child;
      wxTreeItemIdValue cookie;
      child = pTree->GetFirstChild(treeId, cookie);
      while (child.IsOk())
      {
            wxString name = pTree->GetItemText(child);
            char* utf8 = ConvUTF8(name);

            CSiteManagerItemData* data = reinterpret_cast<CSiteManagerItemData* >(pTree->GetItemData(child));
            if (!data)
            {
                  TiXmlNode* pNode = pElement->InsertEndChild(TiXmlElement("Folder"));
                  pNode->InsertEndChild(TiXmlText(utf8));
                  delete [] utf8;

                  Save(pNode->ToElement(), child);
            }
            else
            {
                  TiXmlNode* pNode = pElement->InsertEndChild(TiXmlElement("Server"));
                  SetServer(pNode->ToElement(), data->m_server);

                  TiXmlNode* sub;

                  // Save comments
                  sub = pNode->InsertEndChild(TiXmlElement("Comments"));
                  char* comments = ConvUTF8(data->m_comments);
                  sub->InsertEndChild(TiXmlText(comments));
                  delete [] comments;

                  // Save local dir
                  sub = pNode->InsertEndChild(TiXmlElement("LocalDir"));
                  char* localDir = ConvUTF8(data->m_localDir);
                  sub->InsertEndChild(TiXmlText(localDir));
                  delete [] localDir;

                  // Save remote dir
                  sub = pNode->InsertEndChild(TiXmlElement("RemoteDir"));
                  char* remoteDir = ConvUTF8(data->m_remoteDir.GetSafePath());
                  sub->InsertEndChild(TiXmlText(remoteDir));
                  delete [] remoteDir;

                  pNode->InsertEndChild(TiXmlText(utf8));
                  delete [] utf8;
            }

            child = pTree->GetNextChild(treeId, cookie);
      }

      return false;
}

void CSiteManager::OnNewFolder(wxCommandEvent&event)
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return;

      wxTreeItemId item = pTree->GetSelection();
      if (!item.IsOk())
            return;

      if (pTree->GetItemData(item))
            return;

      if (!Verify())
            return;

      wxString newName = _("New folder");
      int index = 2;
      while (true)
      {
            wxTreeItemId child;
            wxTreeItemIdValue cookie;
            child = pTree->GetFirstChild(item, cookie);
            bool found = false;
            while (child.IsOk())
            {
                  wxString name = pTree->GetItemText(child);
                  int cmp = name.CmpNoCase(newName);
                  if (!cmp)
                  {
                        found = true;
                        break;
                  }

                  child = pTree->GetNextChild(item, cookie);
            }
            if (!found)
                  break;

            newName = _("New folder") + wxString::Format(_T(" %d"), index++);
      }

      wxTreeItemId newItem = pTree->AppendItem(item, newName, 0, 0);
      pTree->SetItemImage(newItem, 1, wxTreeItemIcon_Expanded);
      pTree->SetItemImage(newItem, 1, wxTreeItemIcon_SelectedExpanded);
      pTree->SortChildren(item);
      pTree->SelectItem(newItem);
      pTree->Expand(item);
      pTree->EditLabel(newItem);
}


bool CSiteManager::Verify()
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return true;

      wxTreeItemId item = pTree->GetSelection();
      if (!item.IsOk())
            return true;

      wxTreeItemData* data = pTree->GetItemData(item);
      if (!data)
            return true;

      const wxString& host = XRCCTRL(*this, "ID_HOST", wxTextCtrl)->GetValue();
      if (host == _T(""))
      {
            XRCCTRL(*this, "ID_HOST", wxTextCtrl)->SetFocus();
            wxMessageBox(_("You have to enter a hostname."));
            return false;
      }

      wxString protocolName = XRCCTRL(*this, "ID_PROTOCOL", wxChoice)->GetStringSelection();
      enum ServerProtocol protocol = CServer::GetProtocolFromName(protocolName);
      if (protocol == SFTP &&
            XRCCTRL(*this, "ID_LOGONTYPE", wxChoice)->GetStringSelection() == _("Account"))
      {
            XRCCTRL(*this, "ID_LOGONTYPE", wxChoice)->SetFocus();
            wxMessageBox(_("'Account' logontype not supported by selected protocol"));
            return false;
      }

      CServer server;
      if (protocol != UNKNOWN)
            server.SetProtocol(protocol);

      unsigned long port;
      XRCCTRL(*this, "ID_PORT", wxTextCtrl)->GetValue().ToULong(&port);
      CServerPath path;
      wxString error;
      if (!server.ParseUrl(host, port, _T(""), _T(""), error, path))
      {
            XRCCTRL(*this, "ID_HOST", wxTextCtrl)->SetFocus();
            wxMessageBox(error);
            return false;
      }

      XRCCTRL(*this, "ID_HOST", wxTextCtrl)->SetValue(server.GetHost());
      XRCCTRL(*this, "ID_PORT", wxTextCtrl)->SetValue(wxString::Format(_T("%d"), server.GetPort()));

      protocolName = CServer::GetProtocolName(server.GetProtocol());
      if (protocolName == _T(""))
            CServer::GetProtocolName(FTP);
      XRCCTRL(*this, "ID_PROTOCOL", wxChoice)->SetStringSelection(protocolName);

      if (XRCCTRL(*this, "ID_CHARSET_CUSTOM", wxRadioButton)->GetValue())
      {
            if (XRCCTRL(*this, "ID_ENCODING", wxTextCtrl)->GetValue() == _T(""))
            {
                  XRCCTRL(*this, "ID_ENCODING", wxTextCtrl)->SetFocus();
                  wxMessageBox(_("Need to specify a character encoding"));
                  return false;
            }
      }

      // Require username for non-anonymous logon type
      if (XRCCTRL(*this, "ID_LOGONTYPE", wxChoice)->GetStringSelection() != _("Anonymous") &&
            XRCCTRL(*this, "ID_USER", wxTextCtrl)->GetValue() == _T(""))
      {
            XRCCTRL(*this, "ID_USER", wxTextCtrl)->SetFocus();
            wxMessageBox(_("You have to specify a user name"));
            return false;
      }

      // Require account for account logon type
      if (XRCCTRL(*this, "ID_LOGONTYPE", wxChoice)->GetStringSelection() == _("Account") &&
            XRCCTRL(*this, "ID_ACCOUNT", wxTextCtrl)->GetValue() == _T(""))
      {
            XRCCTRL(*this, "ID_ACCOUNT", wxTextCtrl)->SetFocus();
            wxMessageBox(_("You have to enter an account name"));
            return false;
      }

      return true;
}

void CSiteManager::OnBeginLabelEdit(wxTreeEvent& event)
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
      {
            event.Veto();
            return;
      }

      if (event.GetItem() != pTree->GetSelection())
      {
            if (!Verify())
            {
                  event.Veto();
                  return;
            }
      }

      wxTreeItemId item = event.GetItem();
      if (!item.IsOk() || item == pTree->GetRootItem() || item == m_ownSites || IsPredefinedItem(item))
      {
            event.Veto();
            return;
      }
}

void CSiteManager::OnEndLabelEdit(wxTreeEvent& event)
{
      if (event.IsEditCancelled())
            return;

      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
      {
            event.Veto();
            return;
      }

      wxTreeItemId item = event.GetItem();
      if (item != pTree->GetSelection())
      {
            if (!Verify())
            {
                  event.Veto();
                  return;
            }
      }

      if (!item.IsOk() || item == pTree->GetRootItem() || item == m_ownSites || IsPredefinedItem(item))
      {
            event.Veto();
            return;
      }

      wxString name = event.GetLabel();

      wxTreeItemId parent = pTree->GetItemParent(item);

      wxTreeItemId child;
      wxTreeItemIdValue cookie;
      for (wxTreeItemId child = pTree->GetFirstChild(parent, cookie); child.IsOk(); child = pTree->GetNextChild(parent, cookie))
      {
            if (child == item)
                  continue;
            if (!name.CmpNoCase(pTree->GetItemText(child)))
            {
                  wxMessageBox(_("Name already exists"), _("Cannot rename entry"), wxICON_EXCLAMATION, this);
                  event.Veto();
                  return;
            }
      }

      pTree->SortChildren(parent);
}

void CSiteManager::OnRename(wxCommandEvent& event)
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return;

      wxTreeItemId item = pTree->GetSelection();
      if (!item.IsOk() || item == pTree->GetRootItem() || item == m_ownSites || IsPredefinedItem(item))
            return;

      pTree->EditLabel(item);
}

void CSiteManager::OnDelete(wxCommandEvent& event)
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return;

      wxTreeItemId item = pTree->GetSelection();
      if (!item.IsOk() || item == pTree->GetRootItem() || item == m_ownSites || IsPredefinedItem(item))
            return;

      pTree->Delete(item);
}

void CSiteManager::OnSelChanging(wxTreeEvent& event)
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return;

      if (!Verify())
            event.Veto();

      UpdateServer();
}

void CSiteManager::OnSelChanged(wxTreeEvent& event)
{
      SetCtrlState();
}

void CSiteManager::OnNewSite(wxCommandEvent& event)
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return;

      wxTreeItemId item = pTree->GetSelection();
      if (!item.IsOk() || IsPredefinedItem(item))
            return;

      if (pTree->GetItemData(item))
            return;

      if (!Verify())
            return;

      wxString newName = _("New site");
      int index = 2;
      while (true)
      {
            wxTreeItemId child;
            wxTreeItemIdValue cookie;
            child = pTree->GetFirstChild(item, cookie);
            bool found = false;
            while (child.IsOk())
            {
                  wxString name = pTree->GetItemText(child);
                  int cmp = name.CmpNoCase(newName);
                  if (!cmp)
                  {
                        found = true;
                        break;
                  }

                  child = pTree->GetNextChild(item, cookie);
            }
            if (!found)
                  break;

            newName = _("New site") + wxString::Format(_T(" %d"), index++);
      }

      wxTreeItemId newItem = pTree->AppendItem(item, newName, 2, 2, new CSiteManagerItemData());
      pTree->SortChildren(item);
      pTree->SelectItem(newItem);
      pTree->Expand(item);
      pTree->EditLabel(newItem);
}

void CSiteManager::OnLogontypeSelChanged(wxCommandEvent& event)
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return;

      wxTreeItemId item = pTree->GetSelection();
      if (!item.IsOk())
            return;

      CSiteManagerItemData* data = reinterpret_cast<CSiteManagerItemData* >(pTree->GetItemData(item));
      if (!data)
            return;

      XRCCTRL(*this, "ID_USER", wxTextCtrl)->Enable(event.GetString() != _("Anonymous"));
      XRCCTRL(*this, "ID_PASS", wxTextCtrl)->Enable(event.GetString() == _("Normal") || event.GetString() == _("Account"));
      XRCCTRL(*this, "ID_ACCOUNT", wxTextCtrl)->Enable(event.GetString() == _("Account"));
}

bool CSiteManager::UpdateServer()
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return false;

      wxTreeItemId item = pTree->GetSelection();
      if (!item.IsOk())
            return false;

      CSiteManagerItemData* data = reinterpret_cast<CSiteManagerItemData* >(pTree->GetItemData(item));
      if (!data)
            return false;

      if (IsPredefinedItem(item))
            return true;

      unsigned long port;
      XRCCTRL(*this, "ID_PORT", wxTextCtrl)->GetValue().ToULong(&port);
      data->m_server.SetHost(XRCCTRL(*this, "ID_HOST", wxTextCtrl)->GetValue(), port);

      const wxString& protocolName = XRCCTRL(*this, "ID_PROTOCOL", wxChoice)->GetStringSelection();
      const enum ServerProtocol protocol = CServer::GetProtocolFromName(protocolName);
      if (protocol != UNKNOWN)
            data->m_server.SetProtocol(protocol);
      else
            data->m_server.SetProtocol(FTP);

      wxString logonType = XRCCTRL(*this, "ID_LOGONTYPE", wxChoice)->GetStringSelection();
      if (logonType == _("Normal"))
            data->m_server.SetLogonType(NORMAL);
      else if (logonType == _("Ask for password"))
            data->m_server.SetLogonType(ASK);
      else if (logonType == _("Interactive"))
            data->m_server.SetLogonType(INTERACTIVE);
      else if (logonType == _("Account"))
            data->m_server.SetLogonType(ACCOUNT);
      else
            data->m_server.SetLogonType(ANONYMOUS);

      data->m_server.SetUser(XRCCTRL(*this, "ID_USER", wxTextCtrl)->GetValue(),
                                       XRCCTRL(*this, "ID_PASS", wxTextCtrl)->GetValue());
      data->m_server.SetAccount(XRCCTRL(*this, "ID_ACCOUNT", wxTextCtrl)->GetValue());

      data->m_comments = XRCCTRL(*this, "ID_COMMENTS", wxTextCtrl)->GetValue();

      wxString serverType = XRCCTRL(*this, "ID_SERVERTYPE", wxChoice)->GetStringSelection();
      if (serverType == _T("Unix"))
            data->m_server.SetType(UNIX);
      else if (serverType == _T("Dos"))
            data->m_server.SetType(DOS);
      else if (serverType == _T("VMS"))
            data->m_server.SetType(VMS);
      else if (serverType == _T("MVS"))
            data->m_server.SetType(MVS);
      else if (serverType == _T("VxWorks"))
            data->m_server.SetType(VXWORKS);
      else
            data->m_server.SetType(DEFAULT);

      data->m_localDir = XRCCTRL(*this, "ID_LOCALDIR", wxTextCtrl)->GetValue();
      data->m_remoteDir = CServerPath();
      data->m_remoteDir.SetType(data->m_server.GetType());
      data->m_remoteDir.SetPath(XRCCTRL(*this, "ID_REMOTEDIR", wxTextCtrl)->GetValue());
      int hours, minutes;
#ifdef __WXGTK__
      if (!m_timezoneOffsetHoursChanged)
            hours = data->m_server.GetTimezoneOffset() / 60;
      else
#endif
            hours = XRCCTRL(*this, "ID_TIMEZONE_HOURS", wxSpinCtrl)->GetValue();
#ifdef __WXGTK__
      if (!m_timezoneOffsetMinutesChanged)
            minutes = data->m_server.GetTimezoneOffset() % 60;
      else
#endif
            minutes = XRCCTRL(*this, "ID_TIMEZONE_MINUTES", wxSpinCtrl)->GetValue();

      data->m_server.SetTimezoneOffset(hours * 60 + minutes);

      if (XRCCTRL(*this, "ID_TRANSFERMODE_ACTIVE", wxRadioButton)->GetValue())
            data->m_server.SetPasvMode(MODE_ACTIVE);
      else if (XRCCTRL(*this, "ID_TRANSFERMODE_PASSIVE", wxRadioButton)->GetValue())
            data->m_server.SetPasvMode(MODE_PASSIVE);
      else
            data->m_server.SetPasvMode(MODE_DEFAULT);

      if (XRCCTRL(*this, "ID_LIMITMULTIPLE", wxCheckBox)->GetValue())
      {
#ifdef __WXGTK__
            if (m_limitConnectionsChanged)
#endif
                  data->m_server.MaximumMultipleConnections(XRCCTRL(*this, "ID_MAXMULTIPLE", wxSpinCtrl)->GetValue());
      }
      else
            data->m_server.MaximumMultipleConnections(0);

      if (XRCCTRL(*this, "ID_CHARSET_UTF8", wxRadioButton)->GetValue())
            data->m_server.SetEncodingType(ENCODING_UTF8);
      else if (XRCCTRL(*this, "ID_CHARSET_CUSTOM", wxRadioButton)->GetValue())
      {
            wxString encoding = XRCCTRL(*this, "ID_ENCODING", wxTextCtrl)->GetValue();
            data->m_server.SetEncodingType(ENCODING_CUSTOM, encoding);
      }
      else
            data->m_server.SetEncodingType(ENCODING_AUTO);

      return true;
}

bool CSiteManager::GetServer(CSiteManagerItemData& data)
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return false;

      wxTreeItemId item = pTree->GetSelection();
      if (!item.IsOk())
            return false;

      CSiteManagerItemData* pData = reinterpret_cast<CSiteManagerItemData* >(pTree->GetItemData(item));
      if (!pData)
            return false;

      data = *pData;
      data.m_name = pTree->GetItemText(item);

      return true;
}

void CSiteManager::OnRemoteDirBrowse(wxCommandEvent& event)
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return;

      wxTreeItemId item = pTree->GetSelection();
      if (!item.IsOk())
            return;

      CSiteManagerItemData* data = reinterpret_cast<CSiteManagerItemData* >(pTree->GetItemData(item));
      if (!data)
            return;

      wxDirDialog dlg(this, _("Choose the default local directory"), XRCCTRL(*this, "ID_LOCALDIR", wxTextCtrl)->GetValue(), wxDD_NEW_DIR_BUTTON);
      if (dlg.ShowModal() == wxID_OK)
      {
            XRCCTRL(*this, "ID_LOCALDIR", wxTextCtrl)->SetValue(dlg.GetPath());
      }
}

void CSiteManager::OnItemActivated(wxTreeEvent& event)
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return;

      wxTreeItemId item = pTree->GetSelection();
      if (!item.IsOk())
            return;

      CSiteManagerItemData* data = reinterpret_cast<CSiteManagerItemData* >(pTree->GetItemData(item));
      if (!data)
            return;

      wxCommandEvent cmdEvent;
      OnConnect(cmdEvent);
}

void CSiteManager::OnLimitMultipleConnectionsChanged(wxCommandEvent& event)
{
      XRCCTRL(*this, "ID_MAXMULTIPLE", wxSpinCtrl)->Enable(event.IsChecked());
}

void CSiteManager::SetCtrlState()
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return;

      wxTreeItemId item = pTree->GetSelection();

      const bool predefined = IsPredefinedItem(item);

      CSiteManagerItemData* data = 0;
      if (item.IsOk())
            data = reinterpret_cast<CSiteManagerItemData* >(pTree->GetItemData(item));
      if (!data)
      {
            // Set the control states according if it's possible to use the control
            const bool root_or_predefined = (item == pTree->GetRootItem() || item == m_ownSites || predefined);

            XRCCTRL(*this, "ID_RENAME", wxWindow)->Enable(!root_or_predefined);
            XRCCTRL(*this, "ID_DELETE", wxWindow)->Enable(!root_or_predefined);
            XRCCTRL(*this, "ID_COPY", wxWindow)->Enable(false);
            XRCCTRL(*this, "ID_NOTEBOOK", wxWindow)->Enable(false);
            XRCCTRL(*this, "ID_NEWFOLDER", wxWindow)->Enable(!predefined);
            XRCCTRL(*this, "ID_NEWSITE", wxWindow)->Enable(!predefined);
            XRCCTRL(*this, "ID_CONNECT", wxWindow)->Enable(false);

            // Empty all site information
            XRCCTRL(*this, "ID_HOST", wxTextCtrl)->SetValue(_T(""));
            XRCCTRL(*this, "ID_PORT", wxTextCtrl)->SetValue(_T(""));
            XRCCTRL(*this, "ID_PROTOCOL", wxChoice)->SetStringSelection(_("FTP"));
            XRCCTRL(*this, "ID_LOGONTYPE", wxChoice)->SetStringSelection(_("Anonymous"));
            XRCCTRL(*this, "ID_USER", wxTextCtrl)->SetValue(_T(""));
            XRCCTRL(*this, "ID_PASS", wxTextCtrl)->SetValue(_T(""));
            XRCCTRL(*this, "ID_ACCOUNT", wxTextCtrl)->SetValue(_T(""));
            XRCCTRL(*this, "ID_COMMENTS", wxTextCtrl)->SetValue(_T(""));

            XRCCTRL(*this, "ID_SERVERTYPE", wxChoice)->SetStringSelection(_("Default"));
            XRCCTRL(*this, "ID_LOCALDIR", wxTextCtrl)->SetValue(_T(""));
            XRCCTRL(*this, "ID_REMOTEDIR", wxTextCtrl)->SetValue(_T(""));
            XRCCTRL(*this, "ID_TIMEZONE_HOURS", wxSpinCtrl)->SetValue(0);
            XRCCTRL(*this, "ID_TIMEZONE_MINUTES", wxSpinCtrl)->SetValue(0);

            XRCCTRL(*this, "ID_TRANSFERMODE_DEFAULT", wxRadioButton)->SetValue(true);
            XRCCTRL(*this, "ID_LIMITMULTIPLE", wxCheckBox)->SetValue(false);
            XRCCTRL(*this, "ID_MAXMULTIPLE", wxSpinCtrl)->SetValue(1);

            XRCCTRL(*this, "ID_CHARSET_AUTO", wxRadioButton)->SetValue(true);
            XRCCTRL(*this, "ID_ENCODING", wxTextCtrl)->SetValue(_T(""));
      }
      else
      {
            // Set the control states according if it's possible to use the control
            XRCCTRL(*this, "ID_RENAME", wxWindow)->Enable(!predefined);
            XRCCTRL(*this, "ID_DELETE", wxWindow)->Enable(!predefined);
            XRCCTRL(*this, "ID_COPY", wxWindow)->Enable(true);
            XRCCTRL(*this, "ID_NOTEBOOK", wxWindow)->Enable(true);
            XRCCTRL(*this, "ID_NEWFOLDER", wxWindow)->Enable(false);
            XRCCTRL(*this, "ID_NEWSITE", wxWindow)->Enable(false);
            XRCCTRL(*this, "ID_CONNECT", wxWindow)->Enable(true);

            XRCCTRL(*this, "ID_HOST", wxWindow)->Enable(!predefined);
            XRCCTRL(*this, "ID_HOST", wxTextCtrl)->SetValue(data->m_server.GetHost());
            unsigned int port = data->m_server.GetPort();

            if (port != CServer::GetDefaultPort(data->m_server.GetProtocol()))
                  XRCCTRL(*this, "ID_PORT", wxTextCtrl)->SetValue(wxString::Format(_T("%d"), port));
            else
                  XRCCTRL(*this, "ID_PORT", wxTextCtrl)->SetValue(_T(""));
            XRCCTRL(*this, "ID_PORT", wxWindow)->Enable(!predefined);

            const wxString& protocolName = CServer::GetProtocolName(data->m_server.GetProtocol());
            if (protocolName != _T(""))
                  XRCCTRL(*this, "ID_PROTOCOL", wxChoice)->SetStringSelection(protocolName);
            else
                  XRCCTRL(*this, "ID_PROTOCOL", wxChoice)->SetStringSelection(CServer::GetProtocolName(FTP));
            XRCCTRL(*this, "ID_PROTOCOL", wxWindow)->Enable(!predefined);

            XRCCTRL(*this, "ID_USER", wxTextCtrl)->Enable(!predefined && data->m_server.GetLogonType() != ANONYMOUS);
            XRCCTRL(*this, "ID_PASS", wxTextCtrl)->Enable(!predefined && data->m_server.GetLogonType() == NORMAL || data->m_server.GetLogonType() == ACCOUNT);
            XRCCTRL(*this, "ID_ACCOUNT", wxTextCtrl)->Enable(!predefined && data->m_server.GetLogonType() == ACCOUNT);

            switch (data->m_server.GetLogonType())
            {
            case NORMAL:
                  XRCCTRL(*this, "ID_LOGONTYPE", wxChoice)->SetStringSelection(_("Normal"));
                  break;
            case ASK:
                  XRCCTRL(*this, "ID_LOGONTYPE", wxChoice)->SetStringSelection(_("Ask for password"));
                  break;
            case INTERACTIVE:
                  XRCCTRL(*this, "ID_LOGONTYPE", wxChoice)->SetStringSelection(_("Interactive"));
                  break;
            case ACCOUNT:
                  XRCCTRL(*this, "ID_LOGONTYPE", wxChoice)->SetStringSelection(_("Account"));
                  break;
            default:
                  XRCCTRL(*this, "ID_LOGONTYPE", wxChoice)->SetStringSelection(_("Anonymous"));
                  break;
            }
            XRCCTRL(*this, "ID_LOGONTYPE", wxWindow)->Enable(!predefined);

            XRCCTRL(*this, "ID_USER", wxTextCtrl)->SetValue(data->m_server.GetUser());
            XRCCTRL(*this, "ID_ACCOUNT", wxTextCtrl)->SetValue(data->m_server.GetAccount());
            XRCCTRL(*this, "ID_PASS", wxTextCtrl)->SetValue(data->m_server.GetPass());
            XRCCTRL(*this, "ID_COMMENTS", wxTextCtrl)->SetValue(data->m_comments);
            XRCCTRL(*this, "ID_COMMENTS", wxWindow)->Enable(!predefined);

            switch (data->m_server.GetType())
            {
            case UNIX:
                  XRCCTRL(*this, "ID_SERVERTYPE", wxChoice)->SetStringSelection(_T("Unix"));
                  break;
            case DOS:
                  XRCCTRL(*this, "ID_SERVERTYPE", wxChoice)->SetStringSelection(_T("Dos"));
                  break;
            case MVS:
                  XRCCTRL(*this, "ID_SERVERTYPE", wxChoice)->SetStringSelection(_T("MVS"));
                  break;
            case VMS:
                  XRCCTRL(*this, "ID_SERVERTYPE", wxChoice)->SetStringSelection(_T("VMS"));
                  break;
            case VXWORKS:
                  XRCCTRL(*this, "ID_SERVERTYPE", wxChoice)->SetStringSelection(_T("VxWorks"));
                  break;
            default:
                  XRCCTRL(*this, "ID_SERVERTYPE", wxChoice)->SetStringSelection(_("Default"));
                  break;
            }
            XRCCTRL(*this, "ID_SERVERTYPE", wxWindow)->Enable(!predefined);
            XRCCTRL(*this, "ID_LOCALDIR", wxTextCtrl)->SetValue(data->m_localDir);
            XRCCTRL(*this, "ID_LOCALDIR", wxWindow)->Enable(!predefined);
            XRCCTRL(*this, "ID_REMOTEDIR", wxTextCtrl)->SetValue(data->m_remoteDir.GetPath());
            XRCCTRL(*this, "ID_REMOTEDIR", wxWindow)->Enable(!predefined);
            XRCCTRL(*this, "ID_TIMEZONE_HOURS", wxSpinCtrl)->SetValue(data->m_server.GetTimezoneOffset() / 60);
            XRCCTRL(*this, "ID_TIMEZONE_HOURS", wxWindow)->Enable(!predefined);
            XRCCTRL(*this, "ID_TIMEZONE_MINUTES", wxSpinCtrl)->SetValue(data->m_server.GetTimezoneOffset() % 60);
            XRCCTRL(*this, "ID_TIMEZONE_MINUTES", wxWindow)->Enable(!predefined);
#ifdef __WXGTK__
            m_timezoneOffsetHoursChanged = false;
            m_timezoneOffsetMinutesChanged = false;
            m_limitConnectionsChanged = false;
#endif

            enum PasvMode pasvMode = data->m_server.GetPasvMode();
            if (pasvMode == MODE_ACTIVE)
                  XRCCTRL(*this, "ID_TRANSFERMODE_ACTIVE", wxRadioButton)->SetValue(true);
            else if (pasvMode == MODE_PASSIVE)
                  XRCCTRL(*this, "ID_TRANSFERMODE_PASSIVE", wxRadioButton)->SetValue(true);
            else
                  XRCCTRL(*this, "ID_TRANSFERMODE_DEFAULT", wxRadioButton)->SetValue(true);
            XRCCTRL(*this, "ID_TRANSFERMODE_ACTIVE", wxWindow)->Enable(!predefined);
            XRCCTRL(*this, "ID_TRANSFERMODE_PASSIVE", wxWindow)->Enable(!predefined);
            XRCCTRL(*this, "ID_TRANSFERMODE_DEFAULT", wxWindow)->Enable(!predefined);

            int maxMultiple = data->m_server.MaximumMultipleConnections();
            XRCCTRL(*this, "ID_LIMITMULTIPLE", wxCheckBox)->SetValue(maxMultiple != 0);
            XRCCTRL(*this, "ID_LIMITMULTIPLE", wxWindow)->Enable(!predefined);
            if (maxMultiple != 0)
            {
                  XRCCTRL(*this, "ID_MAXMULTIPLE", wxSpinCtrl)->Enable(!predefined);
                  XRCCTRL(*this, "ID_MAXMULTIPLE", wxSpinCtrl)->SetValue(maxMultiple);
            }
            else
            {
                  XRCCTRL(*this, "ID_MAXMULTIPLE", wxSpinCtrl)->Enable(false);
                  XRCCTRL(*this, "ID_MAXMULTIPLE", wxSpinCtrl)->SetValue(1);
            }

            switch (data->m_server.GetEncodingType())
            {
            default:
            case ENCODING_AUTO:
                  XRCCTRL(*this, "ID_CHARSET_AUTO", wxRadioButton)->SetValue(true);
                  break;
            case ENCODING_UTF8:
                  XRCCTRL(*this, "ID_CHARSET_UTF8", wxRadioButton)->SetValue(true);
                  break;
            case ENCODING_CUSTOM:
                  XRCCTRL(*this, "ID_CHARSET_CUSTOM", wxRadioButton)->SetValue(true);
                  break;
            }
            XRCCTRL(*this, "ID_CHARSET_AUTO", wxWindow)->Enable(!predefined);
            XRCCTRL(*this, "ID_CHARSET_UTF8", wxWindow)->Enable(!predefined);
            XRCCTRL(*this, "ID_CHARSET_CUSTOM", wxWindow)->Enable(!predefined);
            XRCCTRL(*this, "ID_ENCODING", wxTextCtrl)->Enable(!predefined && data->m_server.GetEncodingType() == ENCODING_CUSTOM);
            XRCCTRL(*this, "ID_ENCODING", wxTextCtrl)->SetValue(data->m_server.GetCustomEncoding());
      }
}

void CSiteManager::OnCharsetChange(wxCommandEvent& event)
{
      bool checked = XRCCTRL(*this, "ID_CHARSET_CUSTOM", wxRadioButton)->GetValue();
      XRCCTRL(*this, "ID_ENCODING", wxTextCtrl)->Enable(checked);
}

void CSiteManager::OnProtocolSelChanged(wxCommandEvent& event)
{
}

void CSiteManager::OnCopySite(wxCommandEvent& event)
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return;

      wxTreeItemId item = pTree->GetSelection();
      if (!item.IsOk())
            return;

      CSiteManagerItemData* data = reinterpret_cast<CSiteManagerItemData* >(pTree->GetItemData(item));
      if (!data)
            return;

      if (!Verify())
            return;

      if (!UpdateServer())
            return;

      wxTreeItemId parent;
      if (IsPredefinedItem(item))
            parent = m_ownSites;
      else
            parent = pTree->GetItemParent(item);

      const wxString name = pTree->GetItemText(item);
      wxString newName = wxString::Format(_("Copy of %s"), name.c_str());
      int index = 2;
      while (true)
      {
            wxTreeItemId child;
            wxTreeItemIdValue cookie;
            child = pTree->GetFirstChild(parent, cookie);
            bool found = false;
            while (child.IsOk())
            {
                  wxString name = pTree->GetItemText(child);
                  int cmp = name.CmpNoCase(newName);
                  if (!cmp)
                  {
                        found = true;
                        break;
                  }

                  child = pTree->GetNextChild(parent, cookie);
            }
            if (!found)
                  break;

            newName = wxString::Format(_("Copy (%d) of %s"), index++, name.c_str());
      }

      CSiteManagerItemData* newData = new CSiteManagerItemData();
      *newData = *data;
      wxTreeItemId newItem = pTree->AppendItem(parent, newName, 2, 2, newData);
      pTree->SortChildren(parent);
      pTree->SelectItem(newItem);
      pTree->Expand(parent);
      pTree->EditLabel(newItem);
}

bool CSiteManager::LoadDefaultSites()
{
      const wxString& defaultsDir = wxGetApp().GetDefaultsDir();
      if (defaultsDir == _T(""))
            return false;

      wxFileName name(defaultsDir, _T("fzdefaults.xml"));
      CXmlFile file(name);

      TiXmlElement* pDocument = file.Load();
      if (!pDocument)
            return false;

      TiXmlElement* pElement = pDocument->FirstChildElement("Servers");
      if (!pElement)
            return false;

      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      if (!pTree)
            return false;

      int style = pTree->GetWindowStyle();
      pTree->SetWindowStyle(style | wxTR_HIDE_ROOT);
      wxTreeItemId root = pTree->AddRoot(_T(""), 0, 0);

      m_predefinedSites = pTree->AppendItem(root, _("Predefined Sites"), 0, 0);
      pTree->SetItemImage(m_predefinedSites, 1, wxTreeItemIcon_Expanded);
      pTree->SetItemImage(m_predefinedSites, 1, wxTreeItemIcon_SelectedExpanded);

      CSiteManagerXmlHandler_Tree handler(pTree, m_predefinedSites);

      Load(pElement, &handler);

      return true;
}

bool CSiteManager::IsPredefinedItem(wxTreeItemId item)
{
      wxTreeCtrl *pTree = XRCCTRL(*this, "ID_SITETREE", wxTreeCtrl);
      wxASSERT(pTree);
      if (!pTree)
            return false;

      while (item)
      {
            if (item == m_predefinedSites)
                  return true;
            item = pTree->GetItemParent(item);
      }

      return false;
}

class CSiteManagerXmlHandler_Menu : public CSiteManagerXmlHandler
{
public:
      CSiteManagerXmlHandler_Menu(wxMenu* pMenu, std::map<int, CSiteManagerItemData*> *idMap)
            : m_pMenu(pMenu), m_idMap(idMap)
      {
      }

      virtual bool AddFolder(const wxString& name)
      {
            m_parents.push_back(m_pMenu);
            m_childNames.push_back(name);

            m_pMenu = new wxMenu;

            return true;
      }

      virtual bool AddSite(const wxString& name, CSiteManagerItemData* data)
      {
            wxMenuItem* pItem = m_pMenu->Append(wxID_ANY, name);
            (*m_idMap)[pItem->GetId()] = data;

            return true;
      }

      // Go up a level
      virtual bool LevelUp()
      {
            if (m_parents.empty() || m_childNames.empty())
                  return false;

            wxMenu* pChild = m_pMenu;
            m_pMenu = m_parents.back();
            if (pChild->GetMenuItemCount())
                  m_pMenu->AppendSubMenu(pChild, m_childNames.back());
            else
                  delete pChild;
            m_childNames.pop_back();
            m_parents.pop_back();

            return true;
      }

protected:
      wxMenu* m_pMenu;

      std::map<int, CSiteManagerItemData*> *m_idMap;

      std::list<wxMenu*> m_parents;
      std::list<wxString> m_childNames;
};

wxMenu* CSiteManager::GetSitesMenu()
{
      ClearIdMap();

      // We have to synchronize access to sitemanager.xml so that multiple processed don't write
      // to the same file or one is reading while the other one writes.
      CInterProcessMutex mutex(MUTEX_SITEMANAGER);

      wxMenu* predefinedSites = GetSitesMenu_Predefied(m_idMap);

      CXmlFile file(_T("sitemanager"));
      TiXmlElement* pDocument = file.Load();
      if (!pDocument)
      {
            wxString msg = wxString::Format(_("Could not load \"%s\", please make sure the file is valid and can be accessed.\nAny changes made in the Site Manager will not be saved."), file.GetFileName().GetFullPath().c_str());
            wxMessageBox(msg, _("Error loading xml file"), wxICON_ERROR);

            if (!predefinedSites)
                  return predefinedSites;

            wxMenu *pMenu = new wxMenu;
            wxMenuItem* pItem = pMenu->Append(wxID_ANY, _("No sites available"));
            pItem->Enable(false);
            return pMenu;
      }

      TiXmlElement* pElement = pDocument->FirstChildElement("Servers");
      if (!pElement)
      {
            if (!predefinedSites)
                  return predefinedSites;

            wxMenu *pMenu = new wxMenu;
            wxMenuItem* pItem = pMenu->Append(wxID_ANY, _("No sites available"));
            pItem->Enable(false);
            return pMenu;
      }

      wxMenu* pMenu = new wxMenu;
      CSiteManagerXmlHandler_Menu handler(pMenu, &m_idMap);

      bool res = Load(pElement, &handler);
      if (!res || !pMenu->GetMenuItemCount())
      {
            delete pMenu;
            pMenu = 0;
      }

      if (pMenu)
      {
            if (!predefinedSites)
                  return pMenu;

            wxMenu* pRootMenu = new wxMenu;
            pRootMenu->AppendSubMenu(predefinedSites, _("Predefined Sites"));
            pRootMenu->AppendSubMenu(pMenu, _("My Sites"));

            return pRootMenu;
      }

      if (predefinedSites)
            return predefinedSites;

      pMenu = new wxMenu;
      wxMenuItem* pItem = pMenu->Append(wxID_ANY, _("No sites available"));
      pItem->Enable(false);
      return pMenu;
}

void CSiteManager::ClearIdMap()
{
      for (std::map<int, CSiteManagerItemData*>::iterator iter = m_idMap.begin(); iter != m_idMap.end(); iter++)
            delete iter->second;

      m_idMap.clear();
}

wxMenu* CSiteManager::GetSitesMenu_Predefied(std::map<int, CSiteManagerItemData*> &idMap)
{
      const wxString& defaultsDir = wxGetApp().GetDefaultsDir();
      if (defaultsDir == _T(""))
            return 0;

      wxFileName name(defaultsDir, _T("fzdefaults.xml"));
      CXmlFile file(name);

      TiXmlElement* pDocument = file.Load();
      if (!pDocument)
            return 0;

      TiXmlElement* pElement = pDocument->FirstChildElement("Servers");
      if (!pElement)
            return 0;

      wxMenu* pMenu = new wxMenu;
      CSiteManagerXmlHandler_Menu handler(pMenu, &idMap);

      if (!Load(pElement, &handler))
      {
            delete pMenu;
            return 0;
      }

      if (!pMenu->GetMenuItemCount())
      {
            delete pMenu;
            return 0;
      }

      return pMenu;
}

CSiteManagerItemData* CSiteManager::GetSiteById(int id)
{
      std::map<int, CSiteManagerItemData*>::iterator iter = m_idMap.find(id);

      CSiteManagerItemData *pData;
      if (iter != m_idMap.end())
      {
            pData = iter->second;
            iter->second = 0;
      }
      else
            pData = 0;

      ClearIdMap();

      return pData;
}

#ifdef __WXGTK__
void CSiteManager::OnTimezoneOffsetChanged(wxSpinEvent& event)
{
      if (event.GetId() == XRCID("ID_LIMITMULTIPLE"))
            m_limitConnectionsChanged = true;
      else if (event.GetId() == XRCID("ID_TIMEZONE_HOURS"))
            m_timezoneOffsetHoursChanged = true;
      else
            m_timezoneOffsetMinutesChanged = true;
      event.Skip();
}
#endif

Generated by  Doxygen 1.6.0   Back to index