#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 ||
lang == wxLANGUAGE_JAPANESE)
{
m_wrapOnEveryChar = true;
m_noWrapChars = noWrapChars_Chinese;
}
else
#endif
{
m_wrapOnEveryChar = false;
m_noWrapChars = 0;
}
}
syntax highlighted by Code2HTML, v. 0.9.1