Logo Search packages:      
Sourcecode: filezilla version File versions

wrapengine.cpp

#include "FileZilla.h"
#include "wrapengine.h"
#include <wx/wizard.h>
#include "filezillaapp.h"
#include "ipcmutex.h"
#include "xmlfunctions.h"
#include "buildinfo.h"

#if wxUSE_UNICODE
// Chinese equivalents to ".", "," and ":"
static const wxChar noWrapChars_Chinese[] = { '.', ',', ':', 0x3002, 0xFF0C, 0xFF1A, 0};
// Remark: Chinese (Taiwan) uses ascii punctuation marks though, but those
// don't have to be added, as only characters >= 128 will be wrapped.
#endif

bool CWrapEngine::CanWrapBefore(const wxChar& c)
{
      // Check if this is a punctuation character, we're not allowed
      // to wrap before such a character
      const wxChar* p = m_noWrapChars;
      while (*p)
      {
            if (*p == c)
                  break;

            p++;
      }
      if (!*p)
            return true;

      return false;
}

bool CWrapEngine::WrapTextChinese(wxWindow* parent, wxString &text, unsigned long maxLength)
{
      wxASSERT(text.Find(_T("  ")) == -1);
      wxASSERT(text.Find(_T(" \n")) == -1);
      wxASSERT(text.Find(_T("\n ")) == -1);
      wxASSERT(text.Last() != ' ');
      wxASSERT(text.Last() != '\n');

      // See comment at start of WrapText function what this function does
      wxString wrappedText;

      int width = 0, height = 0;

      const wxChar* str = text.c_str();
      // Scan entire string
      while (*str)
      {
            unsigned int lineLength = 0;

            const wxChar* p = str;

            // Position of last wrappable character
            const wxChar* wrappable = 0;

            bool lastAmpersand = false;
            while (*p)
            {
                  if (*p == '&')
                  {
                        if (!lastAmpersand)
                        {
                              lastAmpersand = true;
                              p++;
                              continue;
                        }
                        else
                              lastAmpersand = false;
                  }
                  std::map<wxChar, unsigned int>::const_iterator iter = m_charWidths.find(*p);
                  if (iter == m_charWidths.end())
                  {
                        // Get width of all individual characters, record width of the current line
                        parent->GetTextExtent(*p, &width, &height);
                        if ((unsigned int)width > maxLength)
                              return false;
                        m_charWidths[*p] = width;
                        lineLength += width;
                  }
                  else
                        lineLength += iter->second;

                  wxASSERT(*p != '\r');
                  if (*p == '\n')
                  {
                        // Wrap on newline
                        wrappedText += wxString(str, p - str + 1);
                        str = p + 1;
                        break;
                  }
                  else if (p != str) // Don't wrap at first character
                  {
                        if (*p == ' ')
                              // Remember position of last space
                              wrappable = p;
                        else if (*p >= 128)
                        {
                              if (CanWrapBefore(*p))
                                    wrappable = p;
                        }
                        else if (*(p - 1) >= 128 && CanWrapBefore(*p))
                        {
                              // Beginning of embedded English text, can wrap before
                              wrappable = p;
                        }
                  }

                  if (lineLength > maxLength && wrappable)
                  {
                        wxString tmp = wxString(str, wrappable - str);
                        if (tmp.Last() == ' ')
                              tmp.RemoveLast();
                        wrappedText += tmp + _T("\n");
                        if (*wrappable != ' ')
                              str = wrappable;
                        else
                              str = wrappable + 1;
                        break;
                  }

                  p++;
            }
            if (!*p)
            {
                  if (lineLength > maxLength)
                  {
                        if (!wrappable)
                              return false;

                        const wxString& tmp = wxString(str, wrappable - str);
                        wrappedText += tmp + _T("\n");
                        if (*wrappable != ' ')
                              str = wrappable;
                        else
                              str = wrappable + 1;
                  }
                  wrappedText += str;
                  break;
            }
      }

#ifdef __WXDEBUG__
      wxString temp = wrappedText;
      wxASSERT(temp.Find(_T("  ")) == -1);
      wxASSERT(temp.Find(_T(" \n")) == -1);
      wxASSERT(temp.Find(_T("\n ")) == -1);
      wxASSERT(temp.Last() != ' ');
      wxASSERT(temp.Last() != '\n');
      temp.Replace(_T("&"), _T(""));
      while (temp != _T(""))
      {
            wxString piece;
            int pos = temp.Find(_T("\n"));
            if (pos == -1)
            {
                  piece = temp;
                  temp = _T("");
            }
            else
            {
                  piece = temp.Left(pos);
                  temp = temp.Mid(pos + 1);
            }
            parent->GetTextExtent(piece, &width, &height);
            wxASSERT(width <= (int)maxLength);
      }
#endif

      text = wrappedText;

      return true;
}

bool CWrapEngine::WrapText(wxWindow* parent, wxString& text, unsigned long maxLength)
{
      /*
      This function wraps the given string so that it's width in pixels does
      not exceed maxLength.
      In the general case, wrapping is done on word boundaries. Thus we scan the
      string for spaces, measuer the length of the words and wrap if line becomes
      too long.
      It has to be done wordwise, as with some languages/fonts, the width in
      pixels of a line is smaller than the sum of the widths of every character.

      A special case are some languages, e.g. Chinese, which don't separate words
      with spaces. In such languages it is allowed to break lines after any
      character.

      Though there are a few exceptions:
      - Don't wrap before punctuation marks
      - Wrap embedded English text fragments only on spaces

      For this kind of languages, a different wrapping algorithm is used.
    */

      if (m_wrapOnEveryChar)
      {
#ifdef __WXDEBUG__
            const wxString original = text;
#endif
            bool res = WrapTextChinese(parent, text, maxLength);
#ifdef __WXDEBUG__
            wxString unwrapped = UnwrapText(text);
            wxASSERT(original == unwrapped);
#endif
            return res;
      }

      wxString wrappedText;

      int width = 0, height = 0;

      int spaceWidth = 0;
      parent->GetTextExtent(_T(" "), &spaceWidth, &height);

      int strLen = text.Length();
      int wrapAfter = -1;
      int start = 0;
      unsigned int lineLength = 0;
      for (int i = 0; i <= strLen; i++)
      {
            if (text[i] != ' ' && text[i] != 0)
                  continue;

            wxString segment;
            if (wrapAfter == -1)
            {
                  segment = text.Mid(start, i - start);
                  wrapAfter = i;
            }
            else
                  segment = text.Mid(wrapAfter + 1, i - wrapAfter - 1);

            segment = wxStripMenuCodes(segment);
            parent->GetTextExtent(segment, &width, &height);

            if ((unsigned int)width > maxLength)
            {
                  // Something quite long. Perhaps it's a URL we can wrap at slashes?

                  while (segment != _T(""))
                  {
                        // Find longest possible subsegment
                        // which can be appended to current line, if there is a current line
                        unsigned int j;
                        int best = -1;

                        for (j = 1; j < segment.Len() - 1; j++)
                        {
                              if (segment[j] == '/' && segment[j + 1] != '/')
                              {
                                    wxString left = segment.Left(j + 1);
                                    int lwidth;
                                    parent->GetTextExtent(left, &lwidth, &height);
                                    if ((unsigned)lwidth <= maxLength)
                                    {
                                          if (lineLength && lineLength + spaceWidth + lwidth > maxLength)
                                          {
                                                if (best == -1)
                                                {
                                                      best = j;
                                                      width = lwidth;
                                                }

                                                break;
                                          }

                                          best = j;
                                          width = lwidth;
                                    }
                                    else
                                          break;
                              }
                        }
                        if (best == -1)
                        {
                              // No suitable slash found
                              return false;
                        }

                        if (wrappedText != _T(""))
                              wrappedText += _T("\n");

                        if (lineLength)
                              wrappedText += text.Mid(start, wrapAfter - start);

                        if (lineLength && lineLength + spaceWidth + width > maxLength)
                              wrappedText += _T("\n");
                        else
                              wrappedText += _T(" ");
                        lineLength = 0;

                        wrappedText += segment.Left(best + 1);
                        segment = segment.Mid(best + 1);

                        parent->GetTextExtent(wrappedText, &width, &height);
                        parent->GetTextExtent(segment, &width, &height);
                        if ((unsigned)width <= maxLength)
                        {
                              break;
                        }
                  }

                  start = i - segment.Len();
                  wrapAfter = i;
                  lineLength = 0;
            }

            if (lineLength + spaceWidth + width > maxLength)
            {
                  if (wrappedText != _T(""))
                        wrappedText += _T("\n");
                  wrappedText += text.Mid(start, wrapAfter - start);
                  if (width + spaceWidth >= (int)maxLength)
                  {
                        if (wrappedText != _T(""))
                              wrappedText += _T("\n");
                        wrappedText += text.Mid(wrapAfter + 1, i - wrapAfter - 1);

                        start = i + 1;
                        wrapAfter = -1;
                        lineLength = 0;
                  }
                  else
                  {
                        start = wrapAfter + 1;
                        wrapAfter = i;
                        lineLength = width;
                  }
            }
            else if (lineLength + spaceWidth + width + spaceWidth >= maxLength)
            {
                  if (wrappedText != _T(""))
                        wrappedText += _T("\n");
                  wrappedText += text.Mid(start, i - start);
                  if (text[i] != ' ')
                        wrappedText += text[i];
                  start = i + 1;
                  wrapAfter = -1;
                  lineLength = 0;
            }
            else
            {
                  if (lineLength)
                        lineLength += spaceWidth;
                  lineLength += width;
                  wrapAfter = i;
            }
      }
      if (start < strLen)
      {
            if (wrappedText != _T(""))
                  wrappedText += _T("\n");
            wrappedText += text.Mid(start);
      }

      text = wrappedText;

      return true;
}

bool CWrapEngine::WrapText(wxWindow* parent, int id, unsigned long maxLength)
{
      wxStaticText* pText = wxDynamicCast(parent->FindWindow(id), wxStaticText);
      if (!pText)
            return false;

      wxString text = pText->GetLabel();
      if (!WrapText(parent, text, maxLength))
            return false;

      pText->SetLabel(text);

      return true;
}

bool CWrapEngine::WrapRecursive(wxWindow* wnd, wxSizer* sizer, int max)
{
      // This function auto-wraps static texts.

      if (max <= 0)
            return false;

      for (unsigned int i = 0; i < sizer->GetChildren().GetCount(); i++)
      {
            wxSizerItem* item = sizer->GetItem(i);
            if (!item || !item->IsShown())
                  continue;

            int rborder = 0;
            if (item->GetFlag() & wxRIGHT)
                  rborder = item->GetBorder();
            int lborder = 0;
            if (item->GetFlag() & wxLEFT)
                  lborder = item->GetBorder();

            wxRect rect = item->GetRect();

            wxSize min = item->GetMinSize();
            if (!min.IsFullySpecified())
                  min = item->CalcMin();
            wxASSERT(min.GetWidth() + rborder + lborder <= sizer->GetMinSize().GetWidth());

            if (min.GetWidth() + item->GetPosition().x + lborder + rborder <= max)
                continue;

            wxWindow* window;
            wxSizer* subSizer = 0;
            if ((window = item->GetWindow()))
            {
                  wxStaticText* text = wxDynamicCast(window, wxStaticText);
                  if (text)
                  {
                        if (max - rect.GetLeft() - rborder - 2 <= 0)
                              continue;

                        wxString str = text->GetLabel();
                        if (!WrapText(text, str, max - wxMax(0, rect.GetLeft()) - rborder - 2))
                              return false;
                        text->SetLabel(str);

                        continue;
                  }

                  wxNotebook* book = wxDynamicCast(window, wxNotebook);
                  if (book)
                  {
                        int maxPageWidth = 0;
                        for (unsigned int i = 0; i < book->GetPageCount(); i++)
                        {
                              wxNotebookPage* page = book->GetPage(i);
                              maxPageWidth = wxMax(maxPageWidth, page->GetRect().GetWidth());
                        }

                        for (unsigned int i = 0; i < book->GetPageCount(); i++)
                        {
                              wxNotebookPage* page = book->GetPage(i);
                              wxRect pageRect = page->GetRect();
                              int pageMax = max - rect.GetLeft() - pageRect.GetLeft() - rborder - rect.GetWidth() + maxPageWidth;
                              if (!WrapRecursive(wnd, page->GetSizer(), pageMax))
                                    return false;
                        }
                        continue;
                  }
            }
            if ((subSizer = item->GetSizer()))
            {
                  int subBorder = 0;

                  // Add border of static box sizer
                  wxStaticBoxSizer* sboxSizer;
                  if ((sboxSizer = wxDynamicCast(subSizer, wxStaticBoxSizer)))
                  {
                        int top, other;
                        sboxSizer->GetStaticBox()->GetBordersForSizer(&top, &other);
                        subBorder += other;
                  }

                  if (!WrapRecursive(0, subSizer, max - rborder - subBorder))
                        return false;
            }
      }

      return true;
}

bool CWrapEngine::WrapRecursive(wxWindow* wnd, double ratio, const char* name /*=""*/, wxSize canvas /*=wxSize()*/, wxSize minRequestedSize /*wxSize()*/)
{
      std::vector<wxWindow*> windows;
      windows.push_back(wnd);
      return WrapRecursive(windows, ratio, name, canvas, minRequestedSize);
}

bool CWrapEngine::WrapRecursive(std::vector<wxWindow*>& windows, double ratio, const char* name /*=""*/, wxSize canvas /*=wxSize()*/, wxSize minRequestedSize /*wxSize()*/)
{
      int maxWidth = GetWidthFromCache(name);
      if (maxWidth)
      {
            for (std::vector<wxWindow*>::iterator iter = windows.begin(); iter != windows.end(); iter++)
            {
                  wxSizer* pSizer = (*iter)->GetSizer();
                  if (!pSizer)
                        continue;

                  pSizer->Layout();
#ifdef __WXDEBUG__
                  bool res =
#endif
                  WrapRecursive(*iter, pSizer, maxWidth);
                  wxASSERT(res);
                  pSizer->Layout();
                  pSizer->Fit(*iter);
                  wxSize size = pSizer->GetMinSize();
                  wxASSERT(size.x <= maxWidth);
            }
            return true;
      }

      wxSize size = minRequestedSize;

      for (std::vector<wxWindow*>::iterator iter = windows.begin(); iter != windows.end(); iter++)
      {
            wxSizer* pSizer = (*iter)->GetSizer();
            if (!pSizer)
                  return false;

            pSizer->Layout();
            size.IncTo(pSizer->GetMinSize());
      }

      double currentRatio = ((double)(size.GetWidth() + canvas.x) / (size.GetHeight() + canvas.y));
      if (ratio >= currentRatio)
      {
            // Nothing to do, can't wrap anything
            return true;
      }

      int max = size.GetWidth();
      int min = wxMin(size.GetWidth(), size.GetHeight());
      if (ratio < 0)
            min = (int)(min * ratio);
      if (min > canvas.x)
            min -= canvas.x;
      int desiredWidth = (min + max) / 2;
      int actualWidth = size.GetWidth();

      double bestRatioDiff = currentRatio - ratio;
      int bestWidth = max;

      while (true)
      {
            wxSize size = minRequestedSize;
            for (std::vector<wxWindow*>::iterator iter = windows.begin(); iter != windows.end(); iter++)
            {
                  wxSizer* pSizer = (*iter)->GetSizer();
                  WrapRecursive(*iter, pSizer, desiredWidth);
                  pSizer->Layout();
                  size.IncTo(pSizer->GetMinSize());
            }

            if (size.GetWidth() > desiredWidth)
            {
                  // Wrapping failed
                  min = desiredWidth;
                  if (max - min < 5)
                        break;
                  desiredWidth = (min + max) / 2;

                  for (std::vector<wxWindow*>::iterator iter = windows.begin(); iter != windows.end(); iter++)
                  {
                        UnwrapRecursive(*iter, (*iter)->GetSizer());
                        (*iter)->GetSizer()->Layout();
                  }
                  continue;
            }
            actualWidth = size.GetWidth();

            double newRatio = ((double)(size.GetWidth() + canvas.x) / (size.GetHeight() + canvas.y));

            if (newRatio < ratio)
            {
                  if (ratio - newRatio < bestRatioDiff)
                  {
                        bestRatioDiff = ratio - newRatio;
                        bestWidth = actualWidth;
                  }

                  if (min >= actualWidth)
                        min = desiredWidth;
                  else
                        min = actualWidth;
            }
            else if (newRatio > ratio)
            {
                  if (newRatio - ratio < bestRatioDiff)
                  {
                        bestRatioDiff = newRatio - ratio;
                        bestWidth = actualWidth;
                  }

                  if (max == actualWidth)
                        break;
                  max = actualWidth;
            }
            else
            {
                  bestRatioDiff = ratio - newRatio;
                  bestWidth = actualWidth;
                  break;
            }

            if (max - min < 2)
                  break;
            desiredWidth = (min + max) / 2;

            for (std::vector<wxWindow*>::iterator iter = windows.begin(); iter != windows.end(); iter++)
            {
                  UnwrapRecursive(*iter, (*iter)->GetSizer());
                  (*iter)->GetSizer()->Layout();
            }

            currentRatio = newRatio;
      }
      for (std::vector<wxWindow*>::iterator iter = windows.begin(); iter != windows.end(); iter++)
      {
            wxSizer* pSizer = (*iter)->GetSizer();
            UnwrapRecursive(*iter, pSizer);
            pSizer->Layout();

            WrapRecursive(*iter, pSizer, bestWidth);
            pSizer->Layout();
            pSizer->Fit(*iter);
            size = pSizer->GetMinSize();
            wxASSERT(size.x <= bestWidth);
      }

      SetWidthToCache(name, bestWidth);

      return true;
}

wxString CWrapEngine::UnwrapText(const wxString& text)
{
      wxString unwrapped;
#if wxUSE_UNICODE
      int lang = wxGetApp().GetCurrentLanguage();
      if (lang == wxLANGUAGE_CHINESE || lang == wxLANGUAGE_CHINESE_SIMPLIFIED ||
            lang == wxLANGUAGE_CHINESE_TRADITIONAL || lang == wxLANGUAGE_CHINESE_HONGKONG ||
            lang == wxLANGUAGE_CHINESE_MACAU || lang == wxLANGUAGE_CHINESE_SINGAPORE ||
            lang == wxLANGUAGE_CHINESE_TAIWAN)
      {
            const wxChar* p = text;
            bool wasAscii = false;
            while (*p)
            {
                  if (*p == '\n')
                  {
                        if (wasAscii)
                              unwrapped += ' ';
                        else if (*(p + 1) < 127)
                        {
                              if ((*(p + 1) != '(' || *(p + 2) != '&') && CanWrapBefore(*(p - 1)))
                                    unwrapped += ' ';
                        }
                  }
                  else if (*p != '\r')
                        unwrapped += *p;

                  if (*p < 127)
                        wasAscii = true;
                  else
                        wasAscii = false;

                  p++;
            }
      }
      else
#endif
      {
            unwrapped = text;
            unwrapped.Replace(_T("\n"), _T(" "));
            unwrapped.Replace(_T("\r"), _T(""));
      }
      return unwrapped;
}

bool CWrapEngine::UnwrapRecursive(wxWindow* wnd, wxSizer* sizer)
{
      for (unsigned int i = 0; i < sizer->GetChildren().GetCount(); i++)
      {
            wxSizerItem* item = sizer->GetItem(i);
            if (!item)
                  continue;

            wxWindow* window;
            wxSizer* subSizer;
            if ((window = item->GetWindow()))
            {
                  wxStaticText* text = wxDynamicCast(window, wxStaticText);
                  if (text)
                  {
                        wxString unwrapped = UnwrapText(text->GetLabel());
                text->SetLabel(unwrapped);

                        continue;
                  }

                  wxNotebook* book = wxDynamicCast(window, wxNotebook);
                  if (book)
                  {
                        for (unsigned int i = 0; i < book->GetPageCount(); i++)
                        {
                              wxNotebookPage* page = book->GetPage(i);
                              UnwrapRecursive(wnd, page->GetSizer());
                        }
                        continue;
                  }
            }
            else if ((subSizer = item->GetSizer()))
            {
                  UnwrapRecursive(wnd, subSizer);
            }
      }

      return true;
}

int CWrapEngine::GetWidthFromCache(const char* name)
{
      if (!name || name == "")
            return 0;

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

      wxFileName file(wxGetApp().GetSettingsDir(), _T("layout.xml"));
      TiXmlElement* pDocument = GetXmlFile(file);

      if (!pDocument)
            return 0;

      TiXmlElement* pElement = pDocument->FirstChildElement("Layout");
      if (!pElement)
      {
            delete pDocument->GetDocument();
            return 0;
      }

      int language = wxGetApp().GetCurrentLanguage();

      TiXmlElement* pLanguage = FindElementWithAttribute(pElement, "Language", "id", language);
      if (!pLanguage)
      {
            delete pDocument->GetDocument();
            return 0;
      }

      TiXmlElement* pDialog = FindElementWithAttribute(pLanguage, "Dialog", "name", name);
      if (!pDialog)
      {
            delete pDocument->GetDocument();
            return 0;
      }

      int value = GetAttributeInt(pDialog, "width");

      delete pDocument->GetDocument();

      return value;
}

void CWrapEngine::SetWidthToCache(const char* name, int width)
{
      if (!name || name == "")
            return;

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

      wxFileName file(wxGetApp().GetSettingsDir(), _T("layout.xml"));
      TiXmlElement* pDocument = GetXmlFile(file);

      if (!pDocument)
            return;

      TiXmlElement* pElement = pDocument->FirstChildElement("Layout");
      if (!pElement)
      {
            delete pDocument->GetDocument();
            return;
      }

      int language = wxGetApp().GetCurrentLanguage();

      TiXmlElement* pLanguage = FindElementWithAttribute(pElement, "Language", "id", language);
      if (!pLanguage)
      {
            delete pDocument->GetDocument();
            return;
      }

      TiXmlElement* pDialog = FindElementWithAttribute(pLanguage, "Dialog", "name", name);
      if (!pDialog)
      {
            pDialog = pLanguage->InsertEndChild(TiXmlElement("Dialog"))->ToElement();
            pDialog->SetAttribute("name", name);
      }

      pDialog->SetAttribute("width", width);
      wxString error;
      SaveXmlFile(file, pDocument, &error);

      delete pDocument->GetDocument();
}

CWrapEngine::CWrapEngine()
{
      CheckLanguage();
}

CWrapEngine::~CWrapEngine()
{
}

bool CWrapEngine::LoadCache()
{
      // We have to synchronize access to layout.xml so that multiple processed don't write
      // to the same file or one is reading while the other one writes.
      CInterProcessMutex mutex(MUTEX_LAYOUT);

      wxFileName file(wxGetApp().GetSettingsDir(), _T("layout.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."), file.GetFullPath().c_str());
            wxMessageBox(msg, _("Error loading xml file"), wxICON_ERROR);

            return false;
      }

      bool cacheValid = true;

      TiXmlElement* pElement = pDocument->FirstChildElement("Layout");
      if (!pElement)
            pElement = pDocument->InsertEndChild(TiXmlElement("Layout"))->ToElement();

      const wxString buildDate = CBuildInfo::GetBuildDateString();
      if (GetTextAttribute(pElement, "Builddate") != buildDate)
      {
            cacheValid = false;
            SetTextAttribute(pElement, "Builddate", buildDate);
      }

      const wxString buildTime = CBuildInfo::GetBuildTimeString();
      if (GetTextAttribute(pElement, "Buildtime") != buildTime)
      {
            cacheValid = false;
            SetTextAttribute(pElement, "Buildtime", buildTime);
      }

      // Enumerate resource file names
      // -----------------------------

      TiXmlElement* pResources = pElement->FirstChildElement("Resources");
      if (!pResources)
            pResources = pElement->InsertEndChild(TiXmlElement("Resources"))->ToElement();

      wxString resourceDir = wxGetApp().GetResourceDir();
      wxDir dir(resourceDir);

      wxLogNull log;

      wxString xrc;
      for (bool found = dir.GetFirst(&xrc, _T("*.xrc")); found; found = dir.GetNext(&xrc))
      {
            if (!wxFileName::FileExists(resourceDir + xrc))
                  continue;

            wxFileName fn(resourceDir + xrc);
            wxDateTime date = fn.GetModificationTime();
            wxLongLong ticks = date.GetTicks();

            TiXmlElement* resourceElement = FindElementWithAttribute(pResources, "xrc", "file", xrc.mb_str());
            if (!resourceElement)
            {
                  resourceElement = pResources->InsertEndChild(TiXmlElement("xrc"))->ToElement();
                  resourceElement->SetAttribute("file", xrc.mb_str());
                  resourceElement->SetAttribute("date", ticks.ToString().mb_str());
                  cacheValid = false;
            }
            else
            {
                  const char* xrcNodeDate = resourceElement->Attribute("date");
                  if (!xrcNodeDate || strcmp(xrcNodeDate, ticks.ToString().mb_str()))
                  {
                        cacheValid = false;

                        resourceElement->SetAttribute("date", ticks.ToString().mb_str());
                  }
            }
      }

      // Get static text font and measure sample text
      wxFrame* pFrame = new wxFrame;
      pFrame->Create(0, -1, _T("Title"), wxDefaultPosition, wxDefaultSize, wxFRAME_TOOL_WINDOW);
      wxStaticText* pText = new wxStaticText(pFrame, -1, _T("foo"));

      wxFont font = pText->GetFont();
      wxString fontDesc = font.GetNativeFontInfoDesc();

      TiXmlElement* pFontElement = pElement->FirstChildElement("Font");
      if (!pFontElement)
            pFontElement = pElement->InsertEndChild(TiXmlElement("Font"))->ToElement();

      if (GetTextAttribute(pFontElement, "font") != fontDesc)
      {
            SetTextAttribute(pFontElement, "font", fontDesc);
            cacheValid = false;
      }

      int width, height;
      pText->GetTextExtent(_T("Just some test string we are measuring. If width or heigh differ from the recorded values, invalidate cache."), &width, &height);

      if (GetAttributeInt(pFontElement, "width") != width ||
            GetAttributeInt(pFontElement, "height") != height)
      {
            cacheValid = false;
            SetAttributeInt(pFontElement, "width", width);
            SetAttributeInt(pFontElement, "height", height);
      }

      pFrame->Destroy();


      if (!cacheValid)
      {
            // Clear all languages
            TiXmlElement* pLanguage = pElement->FirstChildElement("Language");
            while (pLanguage)
            {
                  pElement->RemoveChild(pLanguage);
                  pLanguage = pElement->FirstChildElement("Language");
            }
      }

      // Enumerate language files
      // ------------------------

      const wxLanguageInfo* pInfo = wxLocale::FindLanguageInfo(_T("en"));
      if (pInfo)
      {
            TiXmlElement* languageElement = FindElementWithAttribute(pElement, "Language", "id", pInfo->Language);
            if (!languageElement)
            {
                  languageElement = pElement->InsertEndChild(TiXmlElement("Language"))->ToElement();
                  languageElement->SetAttribute("id", pInfo->Language);
            }
      }


      wxString localesDir = wxGetApp().GetLocalesDir();
      if (localesDir != _T("") && dir.Open(localesDir))
      {
            wxString locale;
            for (bool found = dir.GetFirst(&locale); found; found = dir.GetNext(&locale))
            {
                  if (!wxFileName::FileExists(localesDir + locale + _T("/filezilla.mo")))
                        continue;

                  wxString name;
                  const wxLanguageInfo* pInfo = wxLocale::FindLanguageInfo(locale);
                  if (!pInfo)
                        continue;

                  wxFileName fn(localesDir + locale + _T("/filezilla.mo"));
                  wxDateTime date = fn.GetModificationTime();
                  wxLongLong ticks = date.GetTicks();

                  TiXmlElement* languageElement = FindElementWithAttribute(pElement, "Language", "id", pInfo->Language);
                  if (!languageElement)
                  {
                        languageElement = pElement->InsertEndChild(TiXmlElement("Language"))->ToElement();
                        languageElement->SetAttribute("id", pInfo->Language);
                        languageElement->SetAttribute("date", ticks.ToString().mb_str());
                  }
                  else
                  {
                        const char* languageNodeDate = languageElement->Attribute("date");
                        if (!languageNodeDate || strcmp(languageNodeDate, ticks.ToString().mb_str()))
                        {
                              languageElement->SetAttribute("date", ticks.ToString().mb_str());
                              languageElement->Clear();
                        }
                  }
            }
      }

      // Outdated cache entries are now purged

      wxString error;
      if (!SaveXmlFile(file, pDocument, &error))
      {
            wxString msg = wxString::Format(_("Could not write \"%s\": %s"), file.GetFullPath().c_str(), error.c_str());
            wxMessageBox(msg, _("Error writing xml file"), wxICON_ERROR);
      }

      delete pDocument->GetDocument();

      return true;
}

void CWrapEngine::ClearCache()
{
      // We have to synchronize access to layout.xml so that multiple processed don't write
      // to the same file or one is reading while the other one writes.
      CInterProcessMutex mutex(MUTEX_LAYOUT);

      wxFileName file(wxGetApp().GetSettingsDir(), _T("layout.xml"));
      if (file.FileExists())
            wxRemoveFile(file.GetFullPath());
}

void CWrapEngine::CheckLanguage()
{
      #if wxUSE_UNICODE
      // Just don't bother with wrapping on anything other than UCS-2
      // FIXME: Use charset conversion routines to convert into UCS-2 and back into
      //        local charset if not using unicode.
      int lang = wxGetApp().GetCurrentLanguage();
      if (lang == wxLANGUAGE_CHINESE || lang == wxLANGUAGE_CHINESE_SIMPLIFIED ||
            lang == wxLANGUAGE_CHINESE_TRADITIONAL || lang == wxLANGUAGE_CHINESE_HONGKONG ||
            lang == wxLANGUAGE_CHINESE_MACAU || lang == wxLANGUAGE_CHINESE_SINGAPORE ||
            lang == wxLANGUAGE_CHINESE_TAIWAN)
      {
            m_wrapOnEveryChar = true;
            m_noWrapChars = noWrapChars_Chinese;
      }
      else
#endif
      {
            m_wrapOnEveryChar = false;
            m_noWrapChars = 0;
      }
}

Generated by  Doxygen 1.6.0   Back to index