summaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
Diffstat (limited to 'library')
-rw-r--r--library/CustomGrid.cpp252
-rw-r--r--library/CustomGrid.h17
-rw-r--r--library/customButton.cpp20
-rw-r--r--library/customButton.h6
-rw-r--r--library/fileHandling.cpp342
-rw-r--r--library/fileHandling.h35
-rw-r--r--library/globalFunctions.cpp2
-rw-r--r--library/misc.cpp12
-rw-r--r--library/processXml.cpp216
-rw-r--r--library/processXml.h90
-rw-r--r--library/resources.cpp6
-rw-r--r--library/resources.h4
-rw-r--r--library/sorting.h109
-rw-r--r--library/statusHandler.h13
-rw-r--r--library/zstring.cpp28
-rw-r--r--library/zstring.h9
16 files changed, 731 insertions, 430 deletions
diff --git a/library/CustomGrid.cpp b/library/CustomGrid.cpp
index 95300a2b..cf9adc6e 100644
--- a/library/CustomGrid.cpp
+++ b/library/CustomGrid.cpp
@@ -5,8 +5,6 @@
#include "../algorithm.h"
#include "resources.h"
-using namespace xmlAccess;
-
const unsigned int MIN_ROW_COUNT = 15;
@@ -16,8 +14,11 @@ class CustomGridTable : public wxGridTableBase
public:
CustomGridTable() :
wxGridTableBase(),
- lightBlue(80, 110, 255),
- lightGrey(212, 208, 200),
+ blue(80, 110, 255),
+ grey(212, 208, 200),
+ lightRed(235, 57, 61),
+ lightBlue(63, 206, 233),
+ lightGreen(54, 218, 2),
gridRefUI(NULL),
gridData(NULL),
lastNrRows(0),
@@ -186,29 +187,32 @@ public:
}
- void setupColumns(const std::vector<xmlAccess::XmlGlobalSettings::ColumnTypes>& positions)
+ void setupColumns(const std::vector<xmlAccess::ColumnTypes>& positions)
{
columnPositions = positions;
updateGridSizes(); //add or remove columns
}
- XmlGlobalSettings::ColumnTypes getTypeAtPos(unsigned pos) const
+ xmlAccess::ColumnTypes getTypeAtPos(unsigned pos) const
{
if (pos < columnPositions.size())
return columnPositions[pos];
else
- return XmlGlobalSettings::ColumnTypes(1000);
+ return xmlAccess::ColumnTypes(1000);
}
protected:
virtual const wxColour& getRowColor(int row) = 0; //rows that are filtered out are shown in different color
- std::vector<xmlAccess::XmlGlobalSettings::ColumnTypes> columnPositions;
+ std::vector<xmlAccess::ColumnTypes> columnPositions;
+ wxColour blue;
+ wxColour grey;
+ wxColour lightRed;
wxColour lightBlue;
- wxColour lightGrey;
+ wxColour lightGreen;
GridView* gridRefUI; //(very fast) access to underlying grid data :)
FileCompareResult* gridData;
int lastNrRows;
@@ -230,10 +234,10 @@ public:
//mark filtered rows
if (!cmpLine.selectedForSynchronization)
- return lightBlue;
+ return blue;
//mark directories
else if (cmpLine.fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY)
- return lightGrey;
+ return grey;
else
return *wxWHITE;
}
@@ -254,13 +258,15 @@ public:
{
switch (getTypeAtPos(col))
{
- case XmlGlobalSettings::FILENAME: //filename
+ case xmlAccess::FULL_NAME:
+ return gridLine.fileDescrLeft.fullName.c_str();
+ case xmlAccess::FILENAME: //filename
return wxEmptyString;
- case XmlGlobalSettings::REL_PATH: //relative path
+ case xmlAccess::REL_PATH: //relative path
return gridLine.fileDescrLeft.relativeName.c_str();
- case XmlGlobalSettings::SIZE: //file size
+ case xmlAccess::SIZE: //file size
return _("<Directory>");
- case XmlGlobalSettings::DATE: //date
+ case xmlAccess::DATE: //date
return wxEmptyString;
}
}
@@ -268,16 +274,18 @@ public:
{
switch (getTypeAtPos(col))
{
- case XmlGlobalSettings::FILENAME: //filename
+ case xmlAccess::FULL_NAME:
+ return gridLine.fileDescrLeft.fullName.c_str();
+ case xmlAccess::FILENAME: //filename
return gridLine.fileDescrLeft.relativeName.AfterLast(GlobalResources::FILE_NAME_SEPARATOR).c_str();
- case XmlGlobalSettings::REL_PATH: //relative path
+ case xmlAccess::REL_PATH: //relative path
return gridLine.fileDescrLeft.relativeName.BeforeLast(GlobalResources::FILE_NAME_SEPARATOR).c_str();
- case XmlGlobalSettings::SIZE: //file size
+ case xmlAccess::SIZE: //file size
{
wxString fileSize = gridLine.fileDescrLeft.fileSize.ToString(); //tmp string
return globalFunctions::includeNumberSeparator(fileSize);
}
- case XmlGlobalSettings::DATE: //date
+ case xmlAccess::DATE: //date
return FreeFileSync::utcTimeToLocalString(gridLine.fileDescrLeft.lastWriteTimeRaw);
}
}
@@ -320,8 +328,7 @@ public:
}
- //virtual impl.
- const wxColour& getRowColor(int row) //rows that are filtered out are shown in different color
+ virtual const wxColour& getRowColor(int row) //rows that are filtered out are shown in different color
{
if (gridRefUI && unsigned(row) < gridRefUI->size())
{
@@ -329,15 +336,27 @@ public:
//mark filtered rows
if (!cmpLine.selectedForSynchronization)
- return lightBlue;
+ return blue;
else
- return *wxWHITE;
+ switch (cmpLine.cmpResult)
+ {
+ case FILE_LEFT_SIDE_ONLY:
+ case FILE_RIGHT_SIDE_ONLY:
+ return lightGreen;
+ case FILE_LEFT_NEWER:
+ case FILE_RIGHT_NEWER:
+ return lightBlue;
+ case FILE_DIFFERENT:
+ return lightRed;
+ default:
+ return *wxWHITE;
+ }
}
return *wxWHITE;
}
- //virtual impl.
- wxString GetValue(int row, int col)
+
+ virtual wxString GetValue(int row, int col)
{
if (gridRefUI)
{
@@ -377,8 +396,7 @@ public:
CustomGridTableRight() : CustomGridTable() {}
~CustomGridTableRight() {}
- //virtual impl.
- const wxColour& getRowColor(int row) //rows that are filtered out are shown in different color
+ virtual const wxColour& getRowColor(int row) //rows that are filtered out are shown in different color
{
if (gridRefUI && unsigned(row) < gridRefUI->size())
{
@@ -386,10 +404,10 @@ public:
//mark filtered rows
if (!cmpLine.selectedForSynchronization)
- return lightBlue;
+ return blue;
//mark directories
else if (cmpLine.fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY)
- return lightGrey;
+ return grey;
else
return *wxWHITE;
}
@@ -409,13 +427,15 @@ public:
{
switch (getTypeAtPos(col))
{
- case XmlGlobalSettings::FILENAME: //filename
+ case xmlAccess::FULL_NAME:
+ return gridLine.fileDescrRight.fullName.c_str();
+ case xmlAccess::FILENAME: //filename
return wxEmptyString;
- case XmlGlobalSettings::REL_PATH: //relative path
+ case xmlAccess::REL_PATH: //relative path
return gridLine.fileDescrRight.relativeName.c_str();
- case XmlGlobalSettings::SIZE: //file size
+ case xmlAccess::SIZE: //file size
return _("<Directory>");
- case XmlGlobalSettings::DATE: //date
+ case xmlAccess::DATE: //date
return wxEmptyString;
}
}
@@ -423,16 +443,18 @@ public:
{
switch (getTypeAtPos(col))
{
- case XmlGlobalSettings::FILENAME: //filename
+ case xmlAccess::FULL_NAME:
+ return gridLine.fileDescrRight.fullName.c_str();
+ case xmlAccess::FILENAME: //filename
return gridLine.fileDescrRight.relativeName.AfterLast(GlobalResources::FILE_NAME_SEPARATOR).c_str();
- case XmlGlobalSettings::REL_PATH: //relative path
+ case xmlAccess::REL_PATH: //relative path
return gridLine.fileDescrRight.relativeName.BeforeLast(GlobalResources::FILE_NAME_SEPARATOR).c_str();
- case XmlGlobalSettings::SIZE: //file size
+ case xmlAccess::SIZE: //file size
{
wxString fileSize = gridLine.fileDescrRight.fileSize.ToString(); //tmp string
return globalFunctions::includeNumberSeparator(fileSize);
}
- case XmlGlobalSettings::DATE: //date
+ case xmlAccess::DATE: //date
return FreeFileSync::utcTimeToLocalString(gridLine.fileDescrRight.lastWriteTimeRaw);
}
}
@@ -454,6 +476,7 @@ CustomGrid::CustomGrid(wxWindow *parent,
long style,
const wxString& name) :
wxGrid(parent, id, pos, size, style, name),
+ leadGrid(NULL),
scrollbarsEnabled(true),
m_gridLeft(NULL), m_gridRight(NULL), m_gridMiddle(NULL),
gridDataTable(NULL),
@@ -514,17 +537,17 @@ void CustomGrid::adjustGridHeights() //m_gridLeft, m_gridRight, m_gridMiddle are
{
int yMax = std::max(y1, std::max(y2, y3));
- if (::leadGrid == m_gridLeft) //do not handle case (y1 == yMax) here!!! Avoid back coupling!
+ if (leadGrid == m_gridLeft) //do not handle case (y1 == yMax) here!!! Avoid back coupling!
m_gridLeft->SetMargins(0, 0);
else if (y1 < yMax)
m_gridLeft->SetMargins(0, 50);
- if (::leadGrid == m_gridRight)
+ if (leadGrid == m_gridRight)
m_gridRight->SetMargins(0, 0);
else if (y2 < yMax)
m_gridRight->SetMargins(0, 50);
- if (::leadGrid == m_gridMiddle)
+ if (leadGrid == m_gridMiddle)
m_gridMiddle->SetMargins(0, 0);
else if (y3 < yMax)
m_gridMiddle->SetMargins(0, 50);
@@ -536,6 +559,12 @@ void CustomGrid::adjustGridHeights() //m_gridLeft, m_gridRight, m_gridMiddle are
}
+void CustomGrid::setLeadGrid(const wxGrid* newLead)
+{
+ leadGrid = newLead;
+}
+
+
void CustomGrid::updateGridSizes()
{
assert(gridDataTable);
@@ -559,11 +588,66 @@ void CustomGrid::DrawColLabel(wxDC& dc, int col)
}
-void CustomGrid::setColumnAttributes(const xmlAccess::XmlGlobalSettings::ColumnAttributes& attr)
+xmlAccess::ColumnAttributes CustomGrid::getDefaultColumnAttributes()
+{
+ xmlAccess::ColumnAttributes defaultColumnSettings;
+
+ xmlAccess::ColumnAttrib newEntry;
+
+ newEntry.type = xmlAccess::FULL_NAME;
+ newEntry.visible = false;
+ newEntry.position = 0;
+ newEntry.width = 150;
+ defaultColumnSettings.push_back(newEntry);
+
+ newEntry.type = xmlAccess::FILENAME;
+ newEntry.visible = true;
+ newEntry.position = 1;
+ newEntry.width = 138;
+ defaultColumnSettings.push_back(newEntry);
+
+ newEntry.type = xmlAccess::REL_PATH;
+ newEntry.position = 2;
+ newEntry.width = 118;
+ defaultColumnSettings.push_back(newEntry);
+
+ newEntry.type = xmlAccess::SIZE;
+ newEntry.position = 3;
+ newEntry.width = 67;
+ defaultColumnSettings.push_back(newEntry);
+
+ newEntry.type = xmlAccess::DATE;
+ newEntry.position = 4;
+ newEntry.width = 113;
+ defaultColumnSettings.push_back(newEntry);
+
+ return defaultColumnSettings;
+}
+
+
+xmlAccess::ColumnAttributes CustomGrid::getColumnAttributes()
+{
+ std::sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByPositionAndVisibility);
+
+ xmlAccess::ColumnAttributes output;
+ xmlAccess::ColumnAttrib newEntry;
+ for (unsigned int i = 0; i < columnSettings.size(); ++i)
+ {
+ newEntry = columnSettings[i];
+ if (newEntry.visible)
+ newEntry.width = GetColSize(i); //hidden columns are sorted to the end of vector!
+ output.push_back(newEntry);
+ }
+
+ return output;
+}
+
+
+void CustomGrid::setColumnAttributes(const xmlAccess::ColumnAttributes& attr)
{
//remove special alignment for column "size"
for (int i = 0; i < GetNumberCols(); ++i)
- if (getTypeAtPos(i) == XmlGlobalSettings::SIZE)
+ if (getTypeAtPos(i) == xmlAccess::SIZE)
{
wxGridCellAttr* cellAttributes = GetOrCreateCellAttr(0, i);
cellAttributes->SetAlignment(wxALIGN_LEFT,wxALIGN_CENTRE);
@@ -571,44 +655,23 @@ void CustomGrid::setColumnAttributes(const xmlAccess::XmlGlobalSettings::ColumnA
break;
}
//----------------------------------------------------------------------------------
- setSortMarker(-1); //clear sorting marker
columnSettings.clear();
if (attr.size() == 0)
{ //default settings:
- xmlAccess::XmlGlobalSettings::ColumnAttrib newEntry;
- newEntry.type = xmlAccess::XmlGlobalSettings::FILENAME;
- newEntry.visible = true;
- newEntry.position = 0;
- newEntry.width = 138;
- columnSettings.push_back(newEntry);
-
- newEntry.type = xmlAccess::XmlGlobalSettings::REL_PATH;
- newEntry.position = 1;
- newEntry.width = 118;
- columnSettings.push_back(newEntry);
-
- newEntry.type = xmlAccess::XmlGlobalSettings::SIZE;
- newEntry.position = 2;
- newEntry.width = 67;
- columnSettings.push_back(newEntry);
-
- newEntry.type = xmlAccess::XmlGlobalSettings::DATE;
- newEntry.position = 3;
- newEntry.width = 113;
- columnSettings.push_back(newEntry);
+ columnSettings = getDefaultColumnAttributes();
}
else
{
- for (unsigned int i = 0; i < COLUMN_TYPE_COUNT; ++i)
+ for (unsigned int i = 0; i < xmlAccess::COLUMN_TYPE_COUNT; ++i)
{
- XmlGlobalSettings::ColumnAttrib newEntry;
+ xmlAccess::ColumnAttrib newEntry;
if (i < attr.size())
newEntry = attr[i];
else
{
- newEntry.type = xmlAccess::XmlGlobalSettings::FILENAME;
+ newEntry.type = xmlAccess::FILENAME;
newEntry.visible = true;
newEntry.position = i;
newEntry.width = 100;
@@ -616,18 +679,17 @@ void CustomGrid::setColumnAttributes(const xmlAccess::XmlGlobalSettings::ColumnA
columnSettings.push_back(newEntry);
}
- sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByType);
- for (unsigned int i = 0; i < COLUMN_TYPE_COUNT; ++i) //just be sure that each type exists only once
- columnSettings[i].type = XmlGlobalSettings::ColumnTypes(i);
+ std::sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByType);
+ for (unsigned int i = 0; i < xmlAccess::COLUMN_TYPE_COUNT; ++i) //just be sure that each type exists only once
+ columnSettings[i].type = xmlAccess::ColumnTypes(i);
- sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByPositionOnly);
- for (unsigned int i = 0; i < COLUMN_TYPE_COUNT; ++i) //just be sure that positions are numbered correctly
+ std::sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByPositionOnly);
+ for (unsigned int i = 0; i < xmlAccess::COLUMN_TYPE_COUNT; ++i) //just be sure that positions are numbered correctly
columnSettings[i].position = i;
-
- sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByPositionAndVisibility);
}
- std::vector<XmlGlobalSettings::ColumnTypes> newPositions;
+ std::sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByPositionAndVisibility);
+ std::vector<xmlAccess::ColumnTypes> newPositions;
for (unsigned int i = 0; i < columnSettings.size() && columnSettings[i].visible; ++i) //hidden columns are sorted to the end of vector!
newPositions.push_back(columnSettings[i].type);
@@ -642,7 +704,7 @@ void CustomGrid::setColumnAttributes(const xmlAccess::XmlGlobalSettings::ColumnA
//--------------------------------------------------------------------------------------------------------
//set special alignment for column "size"
for (int i = 0; i < GetNumberCols(); ++i)
- if (getTypeAtPos(i) == XmlGlobalSettings::SIZE)
+ if (getTypeAtPos(i) == xmlAccess::SIZE)
{
wxGridCellAttr* cellAttributes = GetOrCreateCellAttr(0, i);
cellAttributes->SetAlignment(wxALIGN_RIGHT,wxALIGN_CENTRE);
@@ -655,42 +717,26 @@ void CustomGrid::setColumnAttributes(const xmlAccess::XmlGlobalSettings::ColumnA
}
-xmlAccess::XmlGlobalSettings::ColumnAttributes CustomGrid::getColumnAttributes()
-{
- sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByPositionAndVisibility);
-
- xmlAccess::XmlGlobalSettings::ColumnAttributes output;
- xmlAccess::XmlGlobalSettings::ColumnAttrib newEntry;
- for (unsigned int i = 0; i < columnSettings.size(); ++i)
- {
- newEntry = columnSettings[i];
- if (newEntry.visible) //hidden columns are sorted to the end of vector!
- newEntry.width = GetColSize(i);
- output.push_back(newEntry);
- }
-
- return output;
-}
-
-
-XmlGlobalSettings::ColumnTypes CustomGrid::getTypeAtPos(unsigned pos) const
+xmlAccess::ColumnTypes CustomGrid::getTypeAtPos(unsigned pos) const
{
assert(gridDataTable);
return gridDataTable->getTypeAtPos(pos);
}
-wxString CustomGrid::getTypeName(XmlGlobalSettings::ColumnTypes colType)
+wxString CustomGrid::getTypeName(xmlAccess::ColumnTypes colType)
{
switch (colType)
{
- case XmlGlobalSettings::FILENAME:
+ case xmlAccess::FULL_NAME:
+ return _("Full name");
+ case xmlAccess::FILENAME:
return _("Filename");
- case XmlGlobalSettings::REL_PATH:
+ case xmlAccess::REL_PATH:
return _("Relative path");
- case XmlGlobalSettings::SIZE:
+ case xmlAccess::SIZE:
return _("Size");
- case XmlGlobalSettings::DATE:
+ case xmlAccess::DATE:
return _("Date");
default:
return wxEmptyString;
@@ -725,7 +771,7 @@ void CustomGridLeft::DoPrepareDC(wxDC& dc)
wxScrollHelper::DoPrepareDC(dc);
int x, y = 0;
- if (this == ::leadGrid) //avoid back coupling
+ if (this == leadGrid) //avoid back coupling
{
GetViewStart(&x, &y);
m_gridMiddle->Scroll(-1, y); //scroll in y-direction only
@@ -764,7 +810,7 @@ void CustomGridMiddle::DoPrepareDC(wxDC& dc)
wxScrollHelper::DoPrepareDC(dc);
int x, y = 0;
- if (this == ::leadGrid) //avoid back coupling
+ if (this == leadGrid) //avoid back coupling
{
GetViewStart(&x, &y);
m_gridLeft->Scroll(-1, y);
@@ -836,7 +882,7 @@ void CustomGridRight::DoPrepareDC(wxDC& dc)
wxScrollHelper::DoPrepareDC(dc);
int x, y = 0;
- if (this == ::leadGrid) //avoid back coupling
+ if (this == leadGrid) //avoid back coupling
{
GetViewStart(&x, &y);
m_gridLeft->Scroll(x, y);
diff --git a/library/CustomGrid.h b/library/CustomGrid.h
index 97642159..8f392975 100644
--- a/library/CustomGrid.h
+++ b/library/CustomGrid.h
@@ -13,8 +13,6 @@ class CustomGridTable;
class CustomGridTableMiddle;
//##################################################################################
-extern const wxGrid* leadGrid; //this global variable is not very nice...
-
class CustomGrid : public wxGrid
{
public:
@@ -46,22 +44,23 @@ public:
void setSortMarker(const int sortColumn, const wxBitmap* bitmap = &wxNullBitmap);
//set visibility, position and width of columns
- void setColumnAttributes(const xmlAccess::XmlGlobalSettings::ColumnAttributes& attr);
- xmlAccess::XmlGlobalSettings::ColumnAttributes getColumnAttributes();
+ static xmlAccess::ColumnAttributes getDefaultColumnAttributes();
+ xmlAccess::ColumnAttributes getColumnAttributes();
+ void setColumnAttributes(const xmlAccess::ColumnAttributes& attr);
- xmlAccess::XmlGlobalSettings::ColumnTypes getTypeAtPos(unsigned pos) const;
+ xmlAccess::ColumnTypes getTypeAtPos(unsigned pos) const;
- static wxString getTypeName(xmlAccess::XmlGlobalSettings::ColumnTypes colType);
+ static wxString getTypeName(xmlAccess::ColumnTypes colType);
- static const unsigned COLUMN_TYPE_COUNT = 4;
+ void setLeadGrid(const wxGrid* newLead);
protected:
//set visibility, position and width of columns
- xmlAccess::XmlGlobalSettings::ColumnAttributes columnSettings;
-
+ xmlAccess::ColumnAttributes columnSettings;
void adjustGridHeights();
+ const wxGrid* leadGrid; //grid that has user focus
bool scrollbarsEnabled;
CustomGrid* m_gridLeft;
CustomGrid* m_gridRight;
diff --git a/library/customButton.cpp b/library/customButton.cpp
index 5cfa8a5a..02cfdad0 100644
--- a/library/customButton.cpp
+++ b/library/customButton.cpp
@@ -10,15 +10,18 @@ wxButtonWithImage::wxButtonWithImage(wxWindow *parent,
long style,
const wxValidator& validator,
const wxString& name) :
- wxBitmapButton(parent, id, wxNullBitmap, pos, size, style | wxBU_AUTODRAW, validator, name)
+ wxBitmapButton(parent, id, wxNullBitmap, pos, size, style | wxBU_AUTODRAW, validator, name),
+ m_spaceAfter(0),
+ m_spaceBefore(0)
{
setTextLabel(label);
}
-void wxButtonWithImage::setBitmapFront(const wxBitmap& bitmap)
+void wxButtonWithImage::setBitmapFront(const wxBitmap& bitmap, unsigned spaceAfter)
{
- bitmapFront = bitmap;
+ bitmapFront = bitmap;
+ m_spaceAfter = spaceAfter;
refreshButtonLabel();
}
@@ -31,9 +34,10 @@ void wxButtonWithImage::setTextLabel(const wxString& text)
}
-void wxButtonWithImage::setBitmapBack(const wxBitmap& bitmap)
+void wxButtonWithImage::setBitmapBack(const wxBitmap& bitmap, unsigned spaceBefore)
{
- bitmapBack = bitmap;
+ bitmapBack = bitmap;
+ m_spaceBefore = spaceBefore;
refreshButtonLabel();
}
@@ -258,7 +262,7 @@ void wxButtonWithImage::refreshButtonLabel()
//calculate dimensions of new button
const int height = std::max(std::max(bitmapFront.GetHeight(), bitmapText.GetHeight()), bitmapBack.GetHeight());
- const int width = bitmapFront.GetWidth() + bitmapText.GetWidth() + bitmapBack.GetWidth();
+ const int width = bitmapFront.GetWidth() + m_spaceAfter + bitmapText.GetWidth() + m_spaceBefore + bitmapBack.GetWidth();
//create a transparent image
wxImage transparentImage(width, height, false);
@@ -274,12 +278,12 @@ void wxButtonWithImage::refreshButtonLabel()
if (bitmapText.IsOk())
writeToImage(wxImage(bitmapText.ConvertToImage()),
- wxPoint(bitmapFront.GetWidth(), (transparentImage.GetHeight() - bitmapText.GetHeight()) / 2),
+ wxPoint(bitmapFront.GetWidth() + m_spaceAfter, (transparentImage.GetHeight() - bitmapText.GetHeight()) / 2),
transparentImage);
if (bitmapBack.IsOk())
writeToImage(wxImage(bitmapBack.ConvertToImage()),
- wxPoint(bitmapFront.GetWidth() + bitmapText.GetWidth(), (transparentImage.GetHeight() - bitmapBack.GetHeight()) / 2),
+ wxPoint(bitmapFront.GetWidth() + m_spaceAfter + bitmapText.GetWidth() + m_spaceBefore, (transparentImage.GetHeight() - bitmapBack.GetHeight()) / 2),
transparentImage);
//adjust button size
diff --git a/library/customButton.h b/library/customButton.h
index 1f3f50ec..ce43828a 100644
--- a/library/customButton.h
+++ b/library/customButton.h
@@ -23,16 +23,18 @@ public:
const wxValidator& validator = wxDefaultValidator,
const wxString& name = wxButtonNameStr);
- void setBitmapFront(const wxBitmap& bitmap);
+ void setBitmapFront(const wxBitmap& bitmap, unsigned spaceAfter = 0);
void setTextLabel( const wxString& text);
- void setBitmapBack( const wxBitmap& bitmap);
+ void setBitmapBack( const wxBitmap& bitmap, unsigned spaceBefore = 0);
private:
wxBitmap createBitmapFromText(const wxString& text);
void refreshButtonLabel();
wxBitmap bitmapFront;
+ unsigned m_spaceAfter;
wxString textLabel;
+ unsigned m_spaceBefore;
wxBitmap bitmapBack;
};
diff --git a/library/fileHandling.cpp b/library/fileHandling.cpp
index 688d3640..cda81ef5 100644
--- a/library/fileHandling.cpp
+++ b/library/fileHandling.cpp
@@ -1,19 +1,13 @@
#include "fileHandling.h"
#include <wx/intl.h>
#include <wx/msgdlg.h>
-#include "resources.h"
+#include "../algorithm.h"
+#include <wx/filename.h>
#ifdef FFS_WIN
#include <wx/msw/wrapwin.h> //includes "windows.h"
#endif // FFS_WIN
-inline
-bool endsWithPathSeparator(const Zstring& name)
-{
- const size_t len = name.length();
- return len && (name[len - 1] == GlobalResources::FILE_NAME_SEPARATOR);
-}
-
class RecycleBin
{
@@ -89,19 +83,30 @@ void FreeFileSync::removeFile(const Zstring& filename, const bool useRecycleBin)
if (useRecycleBin)
{
if (!moveToRecycleBin(filename))
- throw FileError(Zstring(_("Error moving to recycle bin:")) + wxT(" \"") + filename + wxT("\""));
+ throw FileError(Zstring(_("Error moving to Recycle Bin:")) + wxT("\n\"") + filename + wxT("\""));
return;
}
#ifdef FFS_WIN
+ //initialize file attributes
if (!SetFileAttributes(
- filename.c_str(), //address of filename
- FILE_ATTRIBUTE_NORMAL //attributes to set
- )) throw FileError(Zstring(_("Error deleting file:")) + wxT(" \"") + filename + wxT("\""));
-#endif //FFS_WIN
+ filename.c_str(), //address of filename
+ FILE_ATTRIBUTE_NORMAL)) //attributes to set
+ {
+ Zstring errorMessage = Zstring(_("Error deleting file:")) + wxT("\n\"") + filename + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted());
+ }
+ //remove file, support for \\?\-prefix
+ if (DeleteFile(filename.c_str()) == 0)
+ {
+ Zstring errorMessage = Zstring(_("Error deleting file:")) + wxT("\n\"") + filename + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted());
+ }
+#else
if (!wxRemoveFile(filename.c_str()))
- throw FileError(Zstring(_("Error deleting file:")) + wxT(" \"") + filename + wxT("\""));
+ throw FileError(Zstring(_("Error deleting file:")) + wxT("\n\"") + filename + wxT("\""));
+#endif
}
@@ -112,53 +117,65 @@ void FreeFileSync::removeDirectory(const Zstring& directory, const bool useRecyc
if (useRecycleBin)
{
if (!moveToRecycleBin(directory))
- throw FileError(Zstring(_("Error moving to recycle bin:")) + wxT(" \"") + directory + wxT("\""));
+ throw FileError(Zstring(_("Error moving to Recycle Bin:")) + wxT("\n\"") + directory + wxT("\""));
return;
}
std::vector<Zstring> fileList;
std::vector<Zstring> dirList;
- try
- { //should be executed in own scope so that directory access does not disturb deletion!
- getAllFilesAndDirs(directory, fileList, dirList);
- }
- catch (const FileError& e)
- {
- throw FileError(Zstring(_("Error deleting directory:")) + wxT(" \"") + directory + wxT("\""));
- }
+ getAllFilesAndDirs(directory, fileList, dirList);
for (unsigned int j = 0; j < fileList.size(); ++j)
removeFile(fileList[j], false);
- dirList.insert(dirList.begin(), directory); //this directory will be deleted last
+ dirList.insert(dirList.begin(), directory); //parent directory will be deleted last
for (int j = int(dirList.size()) - 1; j >= 0 ; --j)
{
#ifdef FFS_WIN
+ //initialize file attributes
if (!SetFileAttributes(
dirList[j].c_str(), // address of directory name
FILE_ATTRIBUTE_NORMAL)) // attributes to set
- throw FileError(Zstring(_("Error deleting directory:")) + wxT(" \"") + dirList[j] + wxT("\""));
-#endif // FFS_WIN
+ {
+ Zstring errorMessage = Zstring(_("Error deleting directory:")) + wxT("\n\"") + dirList[j] + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted());
+ }
+ //remove directory, support for \\?\-prefix
+ if (RemoveDirectory(dirList[j].c_str()) == 0)
+ {
+ Zstring errorMessage = Zstring(_("Error deleting directory:")) + wxT("\n\"") + dirList[j] + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted());
+ }
+#else
if (!wxRmdir(dirList[j].c_str()))
- throw FileError(Zstring(_("Error deleting directory:")) + wxT(" \"") + dirList[j] + wxT("\""));
+ throw FileError(Zstring(_("Error deleting directory:")) + wxT("\n\"") + dirList[j] + wxT("\""));
+#endif
}
}
void FreeFileSync::createDirectory(const Zstring& directory, const int level)
{
- if (wxDirExists(directory))
+ if (wxDirExists(directory.c_str()))
return;
if (level == 50) //catch endless recursion
return;
- //try to create directory
- if (wxMkdir(directory.c_str()))
+ //try to create directory, support for \\?\-prefix
+#ifdef FFS_WIN
+ if (CreateDirectory(
+ directory.c_str(), // pointer to a directory path string
+ NULL // pointer to a security descriptor
+ ) != 0)
+ return;
+#else
+ if (wxMkdir(directory.c_str())) //wxMkDir has different signature under Linux!
return;
+#endif
//if not successfull try to create parent folders first
Zstring parentDir;
@@ -176,11 +193,25 @@ void FreeFileSync::createDirectory(const Zstring& directory, const int level)
createDirectory(parentDir, level + 1);
//now creation should be possible
- if (!wxMkdir(directory.c_str()))
+#ifdef FFS_WIN
+ if (CreateDirectory(
+ directory.c_str(), // pointer to a directory path string
+ NULL // pointer to a security descriptor
+ ) == 0)
+ {
+ if (level == 0)
+ {
+ Zstring errorMessage = Zstring(_("Error creating directory:")) + wxT("\n\"") + directory + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted());
+ }
+ }
+#else
+ if (!wxMkdir(directory.c_str())) //wxMkDir has different signature under Linux!
{
if (level == 0)
- throw FileError(Zstring(_("Error creating directory:")) + wxT(" \"") + directory + wxT("\""));
+ throw FileError(Zstring(_("Error creating directory:")) + wxT("\n\"") + directory + wxT("\""));
}
+#endif
}
@@ -189,41 +220,44 @@ void FreeFileSync::copyFolderAttributes(const Zstring& source, const Zstring& ta
#ifdef FFS_WIN
DWORD attr = GetFileAttributes(source.c_str()); // address of the name of a file or directory
if (attr == 0xFFFFFFFF)
- throw FileError(Zstring(_("Error reading folder attributes:")) + wxT(" \"") + source + wxT("\""));
+ {
+ Zstring errorMessage = Zstring(_("Error reading folder attributes:")) + wxT("\n\"") + source + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted());
+ }
if (!SetFileAttributes(
target.c_str(), // address of filename
attr)) // address of attributes to set
- throw FileError(Zstring(_("Error writing folder attributes:")) + wxT(" \"") + target + wxT("\""));
+ {
+ Zstring errorMessage = Zstring(_("Error writing folder attributes:")) + wxT("\n\"") + target + wxT("\"");
+ throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted());
+ }
#elif defined FFS_LINUX
//Linux doesn't use attributes for files or folders
#endif
}
-class GetAllFilesSimple : public wxDirTraverser
+class FilesDirsOnlyTraverser : public FreeFileSync::FullDetailFileTraverser
{
public:
- GetAllFilesSimple(std::vector<Zstring>& files, std::vector<Zstring>& subDirectories) :
+ FilesDirsOnlyTraverser(std::vector<Zstring>& files, std::vector<Zstring>& dirs) :
m_files(files),
- m_dirs(subDirectories) {}
+ m_dirs(dirs) {}
- wxDirTraverseResult OnDir(const wxString& dirname)
+ virtual wxDirTraverseResult OnFile(const Zstring& filename, const FreeFileSync::FileInfo& details)
{
- m_dirs.push_back(dirname.c_str());
+ m_files.push_back(filename);
return wxDIR_CONTINUE;
}
-
- wxDirTraverseResult OnFile(const wxString& filename)
+ virtual wxDirTraverseResult OnDir(const Zstring& dirname)
{
- m_files.push_back(filename.c_str());
+ m_dirs.push_back(dirname);
return wxDIR_CONTINUE;
}
-
- wxDirTraverseResult OnOpenError(const wxString& openerrorname)
+ virtual wxDirTraverseResult OnError(const Zstring& errorText)
{
- wxMessageBox(openerrorname, _("Error"));
- return wxDIR_IGNORE;
+ throw FileError(errorText);
}
private:
@@ -238,11 +272,8 @@ void FreeFileSync::getAllFilesAndDirs(const Zstring& sourceDir, std::vector<Zstr
directories.clear();
//get all files and directories from current directory (and subdirectories)
- wxDir dir(sourceDir.c_str());
- GetAllFilesSimple traverser(files, directories);
-
- if (dir.Traverse(traverser) == (size_t)-1)
- throw FileError(Zstring(_("Error traversing directory:")) + wxT(" \"") + sourceDir + wxT("\""));
+ FilesDirsOnlyTraverser traverser(files, directories);
+ traverseInDetail(sourceDir, false, &traverser);
}
@@ -285,7 +316,7 @@ public:
{
struct stat fileInfo;
if (stat(filename.c_str(), &fileInfo) != 0)
- return m_sink->OnError(Zstring(_("Could not retrieve file info for:")) + wxT(" \"") + filename.c_str() + wxT("\""));
+ return m_sink->OnError(Zstring(_("Could not retrieve file info for:")) + wxT("\n\"") + filename.c_str() + wxT("\""));
FreeFileSync::FileInfo details;
details.lastWriteTimeRaw = fileInfo.st_mtime; //UTC time(ANSI C format); unit: 1 second
@@ -310,115 +341,162 @@ private:
#endif
-bool FreeFileSync::traverseInDetail(const Zstring& directory, FullDetailFileTraverser* sink, const int level)
+class TraverseRecursively
{
-#ifdef FFS_WIN
- if (level == 50) //catch endless recursion
+public:
+ TraverseRecursively(const bool traverseSymbolicLinks, FreeFileSync::FullDetailFileTraverser* sink) :
+ m_traverseSymbolicLinks(traverseSymbolicLinks),
+ m_sink(sink) {}
+
+ bool traverse(const Zstring& directory, const int level)
{
- if (sink->OnError(Zstring(_("Error traversing directory:")) + wxT(" ") + directory) == wxDIR_STOP)
- return false;
- else
- return true;
- }
+#ifdef FFS_WIN
+ if (level == 50) //catch endless recursion
+ {
+ if (m_sink->OnError(Zstring(_("Error traversing directory:")) + wxT("\n\"") + directory + wxT("\"")) == wxDIR_STOP)
+ return false;
+ else
+ return true;
+ }
- Zstring directoryFormatted = directory;
- if (!endsWithPathSeparator(directoryFormatted))
- directoryFormatted += GlobalResources::FILE_NAME_SEPARATOR;
+ Zstring directoryFormatted = directory;
+ if (!FreeFileSync::endsWithPathSeparator(directoryFormatted))
+ directoryFormatted += GlobalResources::FILE_NAME_SEPARATOR;
- const Zstring filespec = directoryFormatted + wxT("*.*");
+ const Zstring filespec = directoryFormatted + DefaultChar('*');
- WIN32_FIND_DATA fileMetaData;
- HANDLE searchHandle = FindFirstFile(filespec.c_str(), //pointer to name of file to search for
- &fileMetaData); //pointer to returned information
+ WIN32_FIND_DATA fileMetaData;
+ HANDLE searchHandle = FindFirstFile(filespec.c_str(), //pointer to name of file to search for
+ &fileMetaData); //pointer to returned information
- if (searchHandle == INVALID_HANDLE_VALUE)
- {
- if (GetLastError() == ERROR_FILE_NOT_FOUND)
- return true;
- //else: we have a problem...
- if (sink->OnError(Zstring(_("Error traversing directory:")) + wxT(" ") + directoryFormatted) == wxDIR_STOP)
- return false;
- else
- return true;
- }
- CloseOnExit dummy(searchHandle);
-
- do
- { //don't return "." and ".."
- const wxChar* name = fileMetaData.cFileName;
- if ( name[0] == wxChar('.') &&
- ((name[1] == wxChar('.') && name[2] == wxChar('\0')) ||
- name[1] == wxChar('\0')))
- continue;
-
- const Zstring fullName = directoryFormatted + name;
- if (fileMetaData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //a directory...
+ if (searchHandle == INVALID_HANDLE_VALUE)
{
- switch (sink->OnDir(fullName))
+ const DWORD lastError = GetLastError();
+ if (lastError == ERROR_FILE_NOT_FOUND)
+ return true;
+
+ //else: we have a problem... report it:
+ Zstring errorMessage = Zstring(_("Error traversing directory:")) + wxT("\n\"") + directory + wxT("\" ") ;
+ if (m_sink->OnError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted(lastError)) == wxDIR_STOP)
+ return false;
+ else
+ return true;
+ }
+ CloseOnExit dummy(searchHandle);
+
+ do
+ { //don't return "." and ".."
+ const wxChar* name = fileMetaData.cFileName;
+ if ( name[0] == wxChar('.') &&
+ ((name[1] == wxChar('.') && name[2] == wxChar('\0')) ||
+ name[1] == wxChar('\0')))
+ continue;
+
+ const Zstring fullName = directoryFormatted + name;
+
+ if (fileMetaData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //a directory...
{
- case wxDIR_IGNORE:
- break;
- case wxDIR_CONTINUE:
- if (!traverseInDetail(fullName, sink, level + 1))
+ switch (m_sink->OnDir(fullName))
+ {
+ case wxDIR_IGNORE:
+ break;
+ case wxDIR_CONTINUE:
+ //traverse into symbolic links, junctions, etc. if requested only:
+ if (m_traverseSymbolicLinks || (~fileMetaData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
+ if (!this->traverse(fullName, level + 1))
+ return false;
+ break;
+ case wxDIR_STOP:
return false;
- else
+ default:
+ assert(false);
break;
- case wxDIR_STOP:
- return false;
- default:
- assert(false);
- break;
+ }
}
- }
- else //a file...
- {
- FileInfo details;
- getWin32FileInformation(fileMetaData, details);
-
- switch (sink->OnFile(fullName, details))
+ else //a file...
{
- case wxDIR_IGNORE:
- case wxDIR_CONTINUE:
- break;
- case wxDIR_STOP:
- return false;
- default:
- assert(false);
- break;
+ FreeFileSync::FileInfo details;
+ getWin32FileInformation(fileMetaData, details);
+
+ switch (m_sink->OnFile(fullName, details))
+ {
+ case wxDIR_IGNORE:
+ case wxDIR_CONTINUE:
+ break;
+ case wxDIR_STOP:
+ return false;
+ default:
+ assert(false);
+ break;
+ }
}
}
- }
- while (FindNextFile(searchHandle, // handle to search
- &fileMetaData)); // pointer to structure for data on found file
+ while (FindNextFile(searchHandle, // handle to search
+ &fileMetaData)); // pointer to structure for data on found file
- if (GetLastError() == ERROR_NO_MORE_FILES)
- return true; //everything okay
- else //an error occured
- {
- if (sink->OnError(Zstring(_("Error traversing directory:")) + wxT(" ") + directoryFormatted) == wxDIR_STOP)
+ const DWORD lastError = GetLastError();
+ if (lastError == ERROR_NO_MORE_FILES)
+ return true; //everything okay
+
+ //else: we have a problem... report it:
+ Zstring errorMessage = Zstring(_("Error traversing directory:")) + wxT("\n\"") + directory + wxT("\" ") ;
+ if (m_sink->OnError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted(lastError)) == wxDIR_STOP)
return false;
else
return true;
- }
#elif defined FFS_LINUX
- //use standard file traverser and enrich output with additional file information
- //could be improved with custom traversing algorithm for optimized performance
- EnhancedFileTraverser traverser(sink);
+ //use standard file traverser and enrich output with additional file information
+ //could be improved with custom traversing algorithm for optimized performance
+ EnhancedFileTraverser traverser(m_sink);
- wxDir dir(directory.c_str());
- if (dir.IsOpened())
- dir.Traverse(traverser);
+ wxDir dir(directory.c_str());
+ if (dir.IsOpened())
+ dir.Traverse(traverser);
- return true;
+ return true;
#else
- adapt this
+ adapt this
#endif
+ }
+
+private:
+ const bool m_traverseSymbolicLinks;
+ FreeFileSync::FullDetailFileTraverser* m_sink;
+};
+
+
+void FreeFileSync::traverseInDetail(const Zstring& directory,
+ const bool traverseSymbolicLinks,
+ FullDetailFileTraverser* sink)
+{
+ TraverseRecursively filewalker(traverseSymbolicLinks, sink);
+ filewalker.traverse(directory, 0);
}
+#ifdef FFS_WIN
+inline
+Zstring getDriveName(const Zstring& directoryName) //GetVolume() doesn't work under Linux!
+{
+ const Zstring volumeName = wxFileName(directoryName.c_str()).GetVolume().c_str();
+ if (volumeName.empty())
+ return Zstring();
+ return volumeName + wxFileName::GetVolumeSeparator().c_str() + GlobalResources::FILE_NAME_SEPARATOR;
+}
+bool FreeFileSync::isFatDrive(const Zstring& directoryName)
+{
+ const Zstring driveName = getDriveName(directoryName);
+ if (driveName.empty())
+ return false;
+ wxChar fileSystem[32];
+ if (!GetVolumeInformation(driveName.c_str(), NULL, 0, NULL, NULL, NULL, fileSystem, 32))
+ return false;
+ return Zstring(fileSystem).StartsWith(wxT("FAT"));
+}
+#endif //FFS_WIN
diff --git a/library/fileHandling.h b/library/fileHandling.h
index 5578ce91..7a1b1842 100644
--- a/library/fileHandling.h
+++ b/library/fileHandling.h
@@ -8,7 +8,8 @@
class FileError //Exception class used to notify file/directory copy/delete errors
{
public:
- FileError(const Zstring& txt) : errorMessage(txt) {}
+ FileError(const Zstring& message) :
+ errorMessage(message) {}
Zstring show() const
{
@@ -22,20 +23,6 @@ private:
namespace FreeFileSync
{
- void getAllFilesAndDirs(const Zstring& sourceDir, std::vector<Zstring>& files, std::vector<Zstring>& directories) throw(FileError);
-
- //recycler
- bool recycleBinExists(); //test existence of Recycle Bin API on current system
-
- //file handling
- void removeDirectory(const Zstring& directory, const bool useRecycleBin);
- void removeFile(const Zstring& filename, const bool useRecycleBin);
- void createDirectory(const Zstring& directory, const int level = 0); //level is used internally only
- void copyFolderAttributes(const Zstring& source, const Zstring& target);
-
-//################################
- //custom traverser with detail information about files
-
struct FileInfo
{
wxULongLong fileSize; //unit: bytes!
@@ -52,8 +39,22 @@ namespace FreeFileSync
virtual wxDirTraverseResult OnError(const Zstring& errorText) = 0;
};
- bool traverseInDetail(const Zstring& directory, FullDetailFileTraverser* sink, const int level = 0); //return value and level are used internally only
-//################################
+ //custom traverser with detail information about files
+ void traverseInDetail(const Zstring& directory, const bool traverseSymbolicLinks, FullDetailFileTraverser* sink);
+ void getAllFilesAndDirs(const Zstring& sourceDir, std::vector<Zstring>& files, std::vector<Zstring>& directories) throw(FileError);
+
+ //recycler
+ bool recycleBinExists(); //test existence of Recycle Bin API on current system
+
+ //file handling
+ void removeDirectory(const Zstring& directory, const bool useRecycleBin);
+ void removeFile(const Zstring& filename, const bool useRecycleBin);
+ void createDirectory(const Zstring& directory, const int level = 0); //level is used internally only
+ void copyFolderAttributes(const Zstring& source, const Zstring& target);
+
+#ifdef FFS_WIN
+ bool isFatDrive(const Zstring& directoryName);
+#endif //FFS_WIN
}
diff --git a/library/globalFunctions.cpp b/library/globalFunctions.cpp
index eed6dfe9..aeeeed45 100644
--- a/library/globalFunctions.cpp
+++ b/library/globalFunctions.cpp
@@ -179,7 +179,7 @@ wxString DebugLog::assembleFileName()
void DebugLog::write(const wxString& logText)
{
++lineCount;
- if (lineCount % 10000 == 0) //prevent logfile from becoming too big
+ if (lineCount % 50000 == 0) //prevent logfile from becoming too big
{
logFile->Close();
wxRemoveFile(logfileName);
diff --git a/library/misc.cpp b/library/misc.cpp
index f5c562c7..0b0bf60b 100644
--- a/library/misc.cpp
+++ b/library/misc.cpp
@@ -25,23 +25,23 @@ void exchangeEscapeChars(wxString& data)
switch (value)
{
case wxChar('\\'):
- output+= wxChar('\\');
+ output += wxChar('\\');
break;
case wxChar('n'):
- output+= wxChar('\n');
+ output += wxChar('\n');
break;
case wxChar('t'):
- output+= wxChar('\t');
+ output += wxChar('\t');
break;
case wxChar('\"'):
- output+= wxChar('\"');
+ output += wxChar('\"');
break;
default:
- output+= value;
+ output += value;
}
}
else
- output+= value;
+ output += value;
++input;
}
diff --git a/library/processXml.cpp b/library/processXml.cpp
index 80ac190b..84783452 100644
--- a/library/processXml.cpp
+++ b/library/processXml.cpp
@@ -4,8 +4,6 @@
#include <wx/intl.h>
#include "globalFunctions.h"
-using namespace globalFunctions;
-using namespace xmlAccess;
//small helper functions
bool readXmlElementValue(std::string& output, const TiXmlElement* parent, const std::string& name);
@@ -23,7 +21,7 @@ void addXmlElement(TiXmlElement* parent, const std::string& name, const bool val
class XmlConfigInput
{
public:
- XmlConfigInput(const wxString& fileName, const XmlType type);
+ XmlConfigInput(const wxString& fileName, const xmlAccess::XmlType type);
~XmlConfigInput() {}
bool loadedSuccessfully()
@@ -32,11 +30,11 @@ public:
}
//read gui settings, all values retrieved are optional, so check for initial values! (== -1)
- bool readXmlGuiConfig(XmlGuiConfig& outputCfg);
+ bool readXmlGuiConfig(xmlAccess::XmlGuiConfig& outputCfg);
//read batch settings, all values retrieved are optional
- bool readXmlBatchConfig(XmlBatchConfig& outputCfg);
+ bool readXmlBatchConfig(xmlAccess::XmlBatchConfig& outputCfg);
//read global settings, valid for both GUI and batch mode, independent from configuration
- bool readXmlGlobalSettings(XmlGlobalSettings& outputCfg);
+ bool readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputCfg);
private:
//read basic FreefileSync settings (used by commandline and GUI), return true if ALL values have been retrieved successfully
@@ -50,17 +48,17 @@ private:
class XmlConfigOutput
{
public:
- XmlConfigOutput(const wxString& fileName, const XmlType type);
+ XmlConfigOutput(const wxString& fileName, const xmlAccess::XmlType type);
~XmlConfigOutput() {}
bool writeToFile();
//write gui settings
- bool writeXmlGuiConfig(const XmlGuiConfig& outputCfg);
+ bool writeXmlGuiConfig(const xmlAccess::XmlGuiConfig& outputCfg);
//write batch settings
- bool writeXmlBatchConfig(const XmlBatchConfig& outputCfg);
+ bool writeXmlBatchConfig(const xmlAccess::XmlBatchConfig& outputCfg);
//write global settings
- bool writeXmlGlobalSettings(const XmlGlobalSettings& outputCfg);
+ bool writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& outputCfg);
private:
//write basic FreefileSync settings (used by commandline and GUI), return true if everything was written successfully
@@ -71,7 +69,7 @@ private:
};
-XmlType xmlAccess::getXmlType(const wxString& filename)
+xmlAccess::XmlType xmlAccess::getXmlType(const wxString& filename)
{
if (!wxFileExists(filename))
return XML_OTHER;
@@ -107,9 +105,12 @@ XmlType xmlAccess::getXmlType(const wxString& filename)
}
-XmlGuiConfig xmlAccess::readGuiConfig(const wxString& filename)
+xmlAccess::XmlGuiConfig xmlAccess::readGuiConfig(const wxString& filename)
{
//load XML
+ if (!wxFileExists(filename))
+ throw FileError(Zstring(_("The file does not exist:")) + wxT(" \"") + filename.c_str() + wxT("\""));
+
XmlConfigInput inputFile(filename, XML_GUI_CONFIG);
XmlGuiConfig outputCfg;
@@ -124,9 +125,12 @@ XmlGuiConfig xmlAccess::readGuiConfig(const wxString& filename)
}
-XmlBatchConfig xmlAccess::readBatchConfig(const wxString& filename)
+xmlAccess::XmlBatchConfig xmlAccess::readBatchConfig(const wxString& filename)
{
//load XML
+ if (!wxFileExists(filename))
+ throw FileError(Zstring(_("The file does not exist:")) + wxT(" \"") + filename.c_str() + wxT("\""));
+
XmlConfigInput inputFile(filename, XML_BATCH_CONFIG);
XmlBatchConfig outputCfg;
@@ -141,9 +145,12 @@ XmlBatchConfig xmlAccess::readBatchConfig(const wxString& filename)
}
-XmlGlobalSettings xmlAccess::readGlobalSettings()
+xmlAccess::XmlGlobalSettings xmlAccess::readGlobalSettings()
{
//load XML
+ if (!wxFileExists(FreeFileSync::GLOBAL_CONFIG_FILE))
+ throw FileError(Zstring(_("The file does not exist:")) + wxT(" \"") + FreeFileSync::GLOBAL_CONFIG_FILE.c_str() + wxT("\""));
+
XmlConfigInput inputFile(FreeFileSync::GLOBAL_CONFIG_FILE, XML_GLOBAL_SETTINGS);
XmlGlobalSettings outputCfg;
@@ -175,7 +182,7 @@ void xmlAccess::writeBatchConfig(const wxString& filename, const XmlBatchConfig&
XmlConfigOutput outputFile(filename, XML_BATCH_CONFIG);
//populate and write XML tree
- if ( !outputFile.writeXmlBatchConfig(outputCfg) || //add GUI layout configuration settings
+ if ( !outputFile.writeXmlBatchConfig(outputCfg) || //add batch configuration settings
!outputFile.writeToFile()) //save XML
throw FileError(Zstring(_("Error writing file:")) + wxT(" \"") + filename.c_str() + wxT("\""));
return;
@@ -194,7 +201,7 @@ void xmlAccess::writeGlobalSettings(const XmlGlobalSettings& outputCfg)
}
-XmlConfigInput::XmlConfigInput(const wxString& fileName, const XmlType type) :
+XmlConfigInput::XmlConfigInput(const wxString& fileName, const xmlAccess::XmlType type) :
loadSuccess(false)
{
if (!wxFileExists(fileName)) //avoid wxWidgets error message when wxFFile receives not existing file
@@ -217,11 +224,11 @@ XmlConfigInput::XmlConfigInput(const wxString& fileName, const XmlType type) :
const char* cfgType = root->Attribute("XmlType");
if (cfgType)
{
- if (type == XML_GUI_CONFIG)
+ if (type == xmlAccess::XML_GUI_CONFIG)
loadSuccess = std::string(cfgType) == "GUI";
- else if (type == XML_BATCH_CONFIG)
+ else if (type == xmlAccess::XML_BATCH_CONFIG)
loadSuccess = std::string(cfgType) == "BATCH";
- else if (type == XML_GLOBAL_SETTINGS)
+ else if (type == xmlAccess::XML_GLOBAL_SETTINGS)
loadSuccess = std::string(cfgType) == "GLOBAL";
}
}
@@ -255,7 +262,7 @@ bool readXmlElementValue(int& output, const TiXmlElement* parent, const std::str
std::string temp;
if (readXmlElementValue(temp, parent, name))
{
- output = stringToInt(temp);
+ output = globalFunctions::stringToInt(temp);
return true;
}
else
@@ -308,6 +315,25 @@ bool readXmlElementValue(bool& output, const TiXmlElement* parent, const std::st
}
+bool readXmlElementValue(xmlAccess::OnError& output, const TiXmlElement* parent, const std::string& name)
+{
+ std::string dummy;
+ if (readXmlElementValue(dummy, parent, name))
+ {
+ if (dummy == "Ignore")
+ output = xmlAccess::ON_ERROR_IGNORE;
+ else if (dummy == "Exit")
+ output = xmlAccess::ON_ERROR_EXIT;
+ else //treat all other input as popup
+ output = xmlAccess::ON_ERROR_POPUP;
+
+ return true;
+ }
+ else
+ return false;
+}
+
+
bool XmlConfigInput::readXmlMainConfig(MainConfiguration& mainCfg, std::vector<FolderPair>& directoryPairs)
{
TiXmlElement* root = doc.RootElement();
@@ -366,13 +392,12 @@ bool XmlConfigInput::readXmlMainConfig(MainConfiguration& mainCfg, std::vector<F
//###########################################################
//other
readXmlElementValue(mainCfg.useRecycleBin, miscSettings, "UseRecycler");
- readXmlElementValue(mainCfg.ignoreErrors, miscSettings, "IgnoreErrors");
return true;
}
-bool XmlConfigInput::readXmlGuiConfig(XmlGuiConfig& outputCfg)
+bool XmlConfigInput::readXmlGuiConfig(xmlAccess::XmlGuiConfig& outputCfg)
{
//read main config
if (!readXmlMainConfig(outputCfg.mainCfg, outputCfg.directoryPairs))
@@ -391,11 +416,18 @@ bool XmlConfigInput::readXmlGuiConfig(XmlGuiConfig& outputCfg)
readXmlElementValue(outputCfg.hideFilteredElements, mainWindow, "HideFiltered");
}
+
+ TiXmlElement* guiConfig = hRoot.FirstChild("GuiConfig").ToElement();
+ if (guiConfig)
+ {
+ readXmlElementValue(outputCfg.ignoreErrors, guiConfig, "IgnoreErrors");
+ }
+
return true;
}
-bool XmlConfigInput::readXmlBatchConfig(XmlBatchConfig& outputCfg)
+bool XmlConfigInput::readXmlBatchConfig(xmlAccess::XmlBatchConfig& outputCfg)
{
//read main config
if (!readXmlMainConfig(outputCfg.mainCfg, outputCfg.directoryPairs))
@@ -411,15 +443,15 @@ bool XmlConfigInput::readXmlBatchConfig(XmlBatchConfig& outputCfg)
TiXmlElement* batchConfig = hRoot.FirstChild("BatchConfig").ToElement();
if (batchConfig)
{
- //read application window size and position
readXmlElementValue(outputCfg.silent, batchConfig, "Silent");
+ readXmlElementValue(outputCfg.handleError, batchConfig, "HandleError");
}
return true;
}
-bool XmlConfigInput::readXmlGlobalSettings(XmlGlobalSettings& outputCfg)
+bool XmlConfigInput::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputCfg)
{
TiXmlElement* root = doc.RootElement();
if (!root) return false;
@@ -427,19 +459,30 @@ bool XmlConfigInput::readXmlGlobalSettings(XmlGlobalSettings& outputCfg)
TiXmlHandle hRoot(root);
//read global settings
- TiXmlElement* global = hRoot.FirstChild("Global").ToElement();
- if (!global) return false;
+ TiXmlElement* global = hRoot.FirstChild("Shared").ToElement();
+ if (global)
+ {
+ //program language
+ readXmlElementValue(outputCfg.shared.programLanguage, global, "Language");
- //program language
- readXmlElementValue(outputCfg.global.programLanguage, global, "Language");
+ //traverse into symbolic links (to folders)
+ readXmlElementValue(outputCfg.shared.traverseSymbolicLinks, global, "TraverseSymbolicLinks");
#ifdef FFS_WIN
- //daylight saving time check
- readXmlElementValue(outputCfg.global.handleDstOnFat32, global, "HandleDaylightSavingTimeOnFAT");
+ //daylight saving time check
+ readXmlElementValue(outputCfg.shared.handleDstOnFat32, global, "HandleDaylightSavingTimeOnFAT");
#endif
+ }
+
+ TiXmlElement* warnings = hRoot.FirstChild("Shared").FirstChild("Warnings").ToElement();
+ if (warnings)
+ {
+ //folder dependency check
+ readXmlElementValue(outputCfg.shared.warningDependentFolders, warnings, "CheckForDependentFolders");
- //folder dependency check
- readXmlElementValue(outputCfg.global.folderDependCheckActive, global, "FolderDependencyCheckActive");
+ //significant difference check
+ readXmlElementValue(outputCfg.shared.warningSignificantDifference, warnings, "CheckForSignificantDifference");
+ }
//gui specific global settings (optional)
TiXmlElement* mainWindow = hRoot.FirstChild("Gui").FirstChild("Windows").FirstChild("Main").ToElement();
@@ -452,6 +495,9 @@ bool XmlConfigInput::readXmlGlobalSettings(XmlGlobalSettings& outputCfg)
readXmlElementValue(outputCfg.gui.posYNotMaximized, mainWindow, "PosY");
readXmlElementValue(outputCfg.gui.isMaximized, mainWindow, "Maximized");
+ readXmlElementValue(outputCfg.gui.deleteOnBothSides, mainWindow, "ManualDeletionOnBothSides");
+ readXmlElementValue(outputCfg.gui.useRecyclerForManualDeletion, mainWindow, "ManualDeletionUseRecycler");
+
//###########################################################
//read column attributes
TiXmlElement* leftColumn = TiXmlHandle(mainWindow).FirstChild("LeftColumns").FirstChild("Column").ToElement();
@@ -464,11 +510,11 @@ bool XmlConfigInput::readXmlGlobalSettings(XmlGlobalSettings& outputCfg)
if (visible && position && width) //may be NULL!!
{
- XmlGlobalSettings::ColumnAttrib newAttrib;
- newAttrib.type = XmlGlobalSettings::ColumnTypes(colType);
+ xmlAccess::ColumnAttrib newAttrib;
+ newAttrib.type = xmlAccess::ColumnTypes(colType);
newAttrib.visible = std::string(visible) != std::string("false");
- newAttrib.position = stringToInt(position);
- newAttrib.width = stringToInt(width);
+ newAttrib.position = globalFunctions::stringToInt(position);
+ newAttrib.width = globalFunctions::stringToInt(width);
outputCfg.gui.columnAttribLeft.push_back(newAttrib);
}
else
@@ -488,11 +534,11 @@ bool XmlConfigInput::readXmlGlobalSettings(XmlGlobalSettings& outputCfg)
if (visible && position && width) //may be NULL!!
{
- XmlGlobalSettings::ColumnAttrib newAttrib;
- newAttrib.type = XmlGlobalSettings::ColumnTypes(colType);
+ xmlAccess::ColumnAttrib newAttrib;
+ newAttrib.type = xmlAccess::ColumnTypes(colType);
newAttrib.visible = std::string(visible) != std::string("false");
- newAttrib.position = stringToInt(position);
- newAttrib.width = stringToInt(width);
+ newAttrib.position = globalFunctions::stringToInt(position);
+ newAttrib.width = globalFunctions::stringToInt(width);
outputCfg.gui.columnAttribRight.push_back(newAttrib);
}
else
@@ -516,6 +562,12 @@ bool XmlConfigInput::readXmlGlobalSettings(XmlGlobalSettings& outputCfg)
TiXmlElement* cfgHistory = hRoot.FirstChild("Gui").FirstChild("History").ToElement();
if (cfgHistory)
{
+ //load max. history size
+ const char* histSizeMax = cfgHistory->Attribute("MaximumSize");
+ if (histSizeMax) //may be NULL!
+ outputCfg.gui.cfgHistoryMaxItems = globalFunctions::stringToInt(histSizeMax);
+
+ //load history elements
TiXmlElement* cfgFile = TiXmlHandle(cfgHistory).FirstChild("File").ToElement();
while (cfgFile)
{
@@ -540,7 +592,7 @@ bool XmlConfigInput::readXmlGlobalSettings(XmlGlobalSettings& outputCfg)
}
-XmlConfigOutput::XmlConfigOutput(const wxString& fileName, const XmlType type) :
+XmlConfigOutput::XmlConfigOutput(const wxString& fileName, const xmlAccess::XmlType type) :
m_fileName(fileName)
{
TiXmlBase::SetCondenseWhiteSpace(false); //do not condense whitespace characters
@@ -549,11 +601,11 @@ XmlConfigOutput::XmlConfigOutput(const wxString& fileName, const XmlType type) :
doc.LinkEndChild(decl);
TiXmlElement* root = new TiXmlElement("FreeFileSync");
- if (type == XML_GUI_CONFIG)
+ if (type == xmlAccess::XML_GUI_CONFIG)
root->SetAttribute("XmlType", "GUI"); //xml configuration type
- else if (type == XML_BATCH_CONFIG)
+ else if (type == xmlAccess::XML_BATCH_CONFIG)
root->SetAttribute("XmlType", "BATCH");
- else if (type == XML_GLOBAL_SETTINGS)
+ else if (type == xmlAccess::XML_GLOBAL_SETTINGS)
root->SetAttribute("XmlType", "GLOBAL");
else
assert(false);
@@ -587,7 +639,7 @@ void addXmlElement(TiXmlElement* parent, const std::string& name, const std::str
void addXmlElement(TiXmlElement* parent, const std::string& name, const int value)
{
- addXmlElement(parent, name, numberToString(value));
+ addXmlElement(parent, name, globalFunctions::numberToString(value));
}
@@ -613,6 +665,19 @@ void addXmlElement(TiXmlElement* parent, const std::string& name, const bool val
}
+void addXmlElement(TiXmlElement* parent, const std::string& name, const xmlAccess::OnError value)
+{
+ if (value == xmlAccess::ON_ERROR_IGNORE)
+ addXmlElement(parent, name, std::string("Ignore"));
+ else if (value == xmlAccess::ON_ERROR_EXIT)
+ addXmlElement(parent, name, std::string("Exit"));
+ else if (value == xmlAccess::ON_ERROR_POPUP)
+ addXmlElement(parent, name, std::string("Popup"));
+ else
+ assert(false);
+}
+
+
bool XmlConfigOutput::writeXmlMainConfig(const MainConfiguration& mainCfg, const std::vector<FolderPair>& directoryPairs)
{
TiXmlElement* root = doc.RootElement();
@@ -670,14 +735,13 @@ bool XmlConfigOutput::writeXmlMainConfig(const MainConfiguration& mainCfg, const
//other
addXmlElement(miscSettings, "UseRecycler", mainCfg.useRecycleBin);
- addXmlElement(miscSettings, "IgnoreErrors", mainCfg.ignoreErrors);
//###########################################################
return true;
}
-bool XmlConfigOutput::writeXmlGuiConfig(const XmlGuiConfig& outputCfg)
+bool XmlConfigOutput::writeXmlGuiConfig(const xmlAccess::XmlGuiConfig& outputCfg)
{
//write main config
if (!writeXmlMainConfig(outputCfg.mainCfg, outputCfg.directoryPairs))
@@ -687,22 +751,24 @@ bool XmlConfigOutput::writeXmlGuiConfig(const XmlGuiConfig& outputCfg)
TiXmlElement* root = doc.RootElement();
if (!root) return false;
- TiXmlElement* guiLayout = new TiXmlElement("GuiConfig");
- root->LinkEndChild(guiLayout);
+ TiXmlElement* guiConfig = new TiXmlElement("GuiConfig");
+ root->LinkEndChild(guiConfig);
TiXmlElement* windows = new TiXmlElement("Windows");
- guiLayout->LinkEndChild(windows);
+ guiConfig->LinkEndChild(windows);
TiXmlElement* mainWindow = new TiXmlElement("Main");
windows->LinkEndChild(mainWindow);
addXmlElement(mainWindow, "HideFiltered", outputCfg.hideFilteredElements);
+ addXmlElement(guiConfig, "IgnoreErrors", outputCfg.ignoreErrors);
+
return true;
}
-bool XmlConfigOutput::writeXmlBatchConfig(const XmlBatchConfig& outputCfg)
+bool XmlConfigOutput::writeXmlBatchConfig(const xmlAccess::XmlBatchConfig& outputCfg)
{
//write main config
if (!writeXmlMainConfig(outputCfg.mainCfg, outputCfg.directoryPairs))
@@ -716,31 +782,42 @@ bool XmlConfigOutput::writeXmlBatchConfig(const XmlBatchConfig& outputCfg)
root->LinkEndChild(batchConfig);
addXmlElement(batchConfig, "Silent", outputCfg.silent);
+ addXmlElement(batchConfig, "HandleError", outputCfg.handleError);
return true;
}
-bool XmlConfigOutput::writeXmlGlobalSettings(const XmlGlobalSettings& outputCfg)
+bool XmlConfigOutput::writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& outputCfg)
{
TiXmlElement* root = doc.RootElement();
if (!root) return false;
//###################################################################
//write global settings
- TiXmlElement* global = new TiXmlElement("Global");
+ TiXmlElement* global = new TiXmlElement("Shared");
root->LinkEndChild(global);
//program language
- addXmlElement(global, "Language", outputCfg.global.programLanguage);
+ addXmlElement(global, "Language", outputCfg.shared.programLanguage);
#ifdef FFS_WIN
//daylight saving time check
- addXmlElement(global, "HandleDaylightSavingTimeOnFAT", outputCfg.global.handleDstOnFat32);
+ addXmlElement(global, "HandleDaylightSavingTimeOnFAT", outputCfg.shared.handleDstOnFat32);
#endif
- //folder dependency check
- addXmlElement(global, "FolderDependencyCheckActive", outputCfg.global.folderDependCheckActive);
+ //traverse into symbolic links (to folders)
+ addXmlElement(global, "TraverseSymbolicLinks", outputCfg.shared.traverseSymbolicLinks);
+
+ //warnings
+ TiXmlElement* warnings = new TiXmlElement("Warnings");
+ global->LinkEndChild(warnings);
+
+ //warning: dependent folders
+ addXmlElement(warnings, "CheckForDependentFolders", outputCfg.shared.warningDependentFolders);
+
+ //significant difference check
+ addXmlElement(warnings, "CheckForSignificantDifference", outputCfg.shared.warningSignificantDifference);
//###################################################################
@@ -763,17 +840,20 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const XmlGlobalSettings& outputCfg)
addXmlElement(mainWindow, "PosY", outputCfg.gui.posYNotMaximized);
addXmlElement(mainWindow, "Maximized", outputCfg.gui.isMaximized);
+ addXmlElement(mainWindow, "ManualDeletionOnBothSides", outputCfg.gui.deleteOnBothSides);
+ addXmlElement(mainWindow, "ManualDeletionUseRecycler", outputCfg.gui.useRecyclerForManualDeletion);
+
//write column attributes
TiXmlElement* leftColumn = new TiXmlElement("LeftColumns");
mainWindow->LinkEndChild(leftColumn);
- XmlGlobalSettings::ColumnAttributes columnAtrribLeftCopy = outputCfg.gui.columnAttribLeft; //can't change const vector
+ xmlAccess::ColumnAttributes columnAtrribLeftCopy = outputCfg.gui.columnAttribLeft; //can't change const vector
sort(columnAtrribLeftCopy.begin(), columnAtrribLeftCopy.end(), xmlAccess::sortByType);
for (unsigned int i = 0; i < columnAtrribLeftCopy.size(); ++i)
{
TiXmlElement* subElement = new TiXmlElement("Column");
leftColumn->LinkEndChild(subElement);
- const XmlGlobalSettings::ColumnAttrib& colAttrib = columnAtrribLeftCopy[i];
+ const xmlAccess::ColumnAttrib& colAttrib = columnAtrribLeftCopy[i];
if (colAttrib.visible) subElement->SetAttribute("Visible", "true");
else subElement->SetAttribute("Visible", "false");
subElement->SetAttribute("Position", colAttrib.position);
@@ -782,14 +862,14 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const XmlGlobalSettings& outputCfg)
TiXmlElement* rightColumn = new TiXmlElement("RightColumns");
mainWindow->LinkEndChild(rightColumn);
- XmlGlobalSettings::ColumnAttributes columnAtrribRightCopy = outputCfg.gui.columnAttribRight;
+ xmlAccess::ColumnAttributes columnAtrribRightCopy = outputCfg.gui.columnAttribRight;
sort(columnAtrribRightCopy.begin(), columnAtrribRightCopy.end(), xmlAccess::sortByType);
for (unsigned int i = 0; i < columnAtrribRightCopy.size(); ++i)
{
TiXmlElement* subElement = new TiXmlElement("Column");
rightColumn->LinkEndChild(subElement);
- const XmlGlobalSettings::ColumnAttrib& colAttrib = columnAtrribRightCopy[i];
+ const xmlAccess::ColumnAttrib& colAttrib = columnAtrribRightCopy[i];
if (colAttrib.visible) subElement->SetAttribute("Visible", "true");
else subElement->SetAttribute("Visible", "false");
subElement->SetAttribute("Position", colAttrib.position);
@@ -803,10 +883,11 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const XmlGlobalSettings& outputCfg)
TiXmlElement* cfgHistory = new TiXmlElement("History");
gui->LinkEndChild(cfgHistory);
+ cfgHistory->SetAttribute("MaximumSize", globalFunctions::numberToString(outputCfg.gui.cfgHistoryMaxItems));
+
for (unsigned int i = 0; i < outputCfg.gui.cfgFileHistory.size(); ++i)
addXmlElement(cfgHistory, "File", std::string(outputCfg.gui.cfgFileHistory[i].ToUTF8()));
-
//###################################################################
//write global batch settings
@@ -863,9 +944,14 @@ int xmlAccess::retrieveSystemLanguage()
//case wxLANGUAGE_JAPANESE:
//case wxLANGUAGE_POLISH:
-
default:
- //all the rest: wxLANGUAGE_ENGLISH;
return lang;
}
}
+
+
+void xmlAccess::XmlGlobalSettings::_Shared::resetWarnings()
+{
+ warningDependentFolders = true;
+ warningSignificantDifference = true;
+}
diff --git a/library/processXml.h b/library/processXml.h
index 5f3f8ef9..7b838958 100644
--- a/library/processXml.h
+++ b/library/processXml.h
@@ -9,6 +9,13 @@ using namespace FreeFileSync;
namespace xmlAccess
{
+ enum OnError
+ {
+ ON_ERROR_POPUP,
+ ON_ERROR_IGNORE,
+ ON_ERROR_EXIT
+ };
+
enum XmlType
{
XML_GUI_CONFIG,
@@ -17,28 +24,49 @@ namespace xmlAccess
XML_OTHER
};
- XmlType getXmlType(const wxString& filename);
+ enum ColumnTypes
+ {
+ FILENAME = 0,
+ REL_PATH,
+ SIZE,
+ DATE,
+ FULL_NAME
+ };
+ const unsigned COLUMN_TYPE_COUNT = 5;
+ struct ColumnAttrib
+ {
+ ColumnTypes type;
+ bool visible;
+ unsigned position;
+ int width;
+ };
+ typedef std::vector<ColumnAttrib> ColumnAttributes;
+
+ XmlType getXmlType(const wxString& filename);
+//---------------------------------------------------------------------
struct XmlGuiConfig
{
- XmlGuiConfig() : hideFilteredElements(false) {} //initialize values
+ XmlGuiConfig() : hideFilteredElements(false), ignoreErrors(false) {} //initialize values
MainConfiguration mainCfg;
std::vector<FolderPair> directoryPairs;
bool hideFilteredElements;
+ bool ignoreErrors; //reaction on error situation during synchronization
};
struct XmlBatchConfig
{
- XmlBatchConfig() : silent(false) {}
+ XmlBatchConfig() : silent(false), handleError(ON_ERROR_POPUP) {}
MainConfiguration mainCfg;
std::vector<FolderPair> directoryPairs;
bool silent;
+ OnError handleError; //reaction on error situation during synchronization
};
int retrieveSystemLanguage();
@@ -47,40 +75,30 @@ namespace xmlAccess
struct XmlGlobalSettings
{
//---------------------------------------------------------------------
-//internal structures:
- enum ColumnTypes
- {
- FILENAME = 0,
- REL_PATH,
- SIZE,
- DATE
- };
-
- struct ColumnAttrib
- {
- ColumnTypes type;
- bool visible;
- unsigned position;
- int width;
- };
- typedef std::vector<ColumnAttrib> ColumnAttributes;
-
-//---------------------------------------------------------------------
- struct _Global
+ struct _Shared
{
- _Global() :
+ _Shared() :
programLanguage(retrieveSystemLanguage()),
#ifdef FFS_WIN
handleDstOnFat32(true),
#endif
- folderDependCheckActive(true) {}
+ traverseSymbolicLinks(false)
+ {
+ resetWarnings();
+ }
int programLanguage;
#ifdef FFS_WIN
bool handleDstOnFat32;
#endif
- bool folderDependCheckActive;
- } global;
+ bool traverseSymbolicLinks;
+
+ //warnings
+ void resetWarnings();
+
+ bool warningDependentFolders;
+ bool warningSignificantDifference;
+ } shared;
//---------------------------------------------------------------------
struct _Gui
@@ -92,10 +110,13 @@ namespace xmlAccess
posYNotMaximized(wxDefaultCoord),
isMaximized(false),
#ifdef FFS_WIN
- commandLineFileManager(wxT("explorer /select, %x"))
+ commandLineFileManager(wxT("explorer /select, %name")),
#elif defined FFS_LINUX
- commandLineFileManager(wxT("konqueror \"%path\""))
+ commandLineFileManager(wxT("konqueror \"%path\"")),
#endif
+ cfgHistoryMaxItems(10),
+ deleteOnBothSides(false),
+ useRecyclerForManualDeletion(FreeFileSync::recycleBinExists()) //enable if OS supports it; else user will have to activate first and then get an error message
{}
int widthNotMaximized;
@@ -106,8 +127,11 @@ namespace xmlAccess
ColumnAttributes columnAttribLeft;
ColumnAttributes columnAttribRight;
- std::vector<wxString> cfgFileHistory;
wxString commandLineFileManager;
+ std::vector<wxString> cfgFileHistory;
+ unsigned cfgHistoryMaxItems;
+ bool deleteOnBothSides;
+ bool useRecyclerForManualDeletion;
} gui;
//---------------------------------------------------------------------
@@ -116,21 +140,21 @@ namespace xmlAccess
inline
- bool sortByType(const XmlGlobalSettings::ColumnAttrib& a, const XmlGlobalSettings::ColumnAttrib& b)
+ bool sortByType(const ColumnAttrib& a, const ColumnAttrib& b)
{
return a.type < b.type;
}
inline
- bool sortByPositionOnly(const XmlGlobalSettings::ColumnAttrib& a, const XmlGlobalSettings::ColumnAttrib& b)
+ bool sortByPositionOnly(const ColumnAttrib& a, const ColumnAttrib& b)
{
return a.position < b.position;
}
inline
- bool sortByPositionAndVisibility(const XmlGlobalSettings::ColumnAttrib& a, const XmlGlobalSettings::ColumnAttrib& b)
+ bool sortByPositionAndVisibility(const ColumnAttrib& a, const ColumnAttrib& b)
{
if (a.visible == false) //hidden elements shall appear at end of vector
return false;
diff --git a/library/resources.cpp b/library/resources.cpp
index c60c259c..4a9d0369 100644
--- a/library/resources.cpp
+++ b/library/resources.cpp
@@ -64,10 +64,14 @@ GlobalResources::GlobalResources()
bitmapResource[wxT("filter active.png")] = (bitmapFilterOn = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("filter not active.png")] = (bitmapFilterOff = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("warning.png")] = (bitmapWarning = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("warningSmall.png")] = (bitmapWarningSmall = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("error.png")] = (bitmapError = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("small arrow up.png"]) = (bitmapSmallUp = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("small arrow down.png")] = (bitmapSmallDown = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("save.png")] = (bitmapSave = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("load.png")] = (bitmapLoad = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("FFS.png")] = (bitmapFFS = new wxBitmap(wxNullBitmap));
+ bitmapResource[wxT("FFS paused.png")] = (bitmapFFSPaused = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("deleteFile.png")] = (bitmapDeleteFile = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("gpl.png")] = (bitmapGPL = new wxBitmap(wxNullBitmap));
bitmapResource[wxT("statusPause.png")] = (bitmapStatusPause = new wxBitmap(wxNullBitmap));
@@ -102,6 +106,8 @@ GlobalResources::GlobalResources()
//init all the other resource files
animationMoney = new wxAnimation(wxNullAnimation);
animationSync = new wxAnimation(wxNullAnimation);
+
+ programIcon = &wxNullIcon;
}
diff --git a/library/resources.h b/library/resources.h
index 4eec185e..24e8d027 100644
--- a/library/resources.h
+++ b/library/resources.h
@@ -63,10 +63,14 @@ public:
wxBitmap* bitmapFilterOn;
wxBitmap* bitmapFilterOff;
wxBitmap* bitmapWarning;
+ wxBitmap* bitmapWarningSmall;
+ wxBitmap* bitmapError;
wxBitmap* bitmapSmallUp;
wxBitmap* bitmapSmallDown;
wxBitmap* bitmapSave;
+ wxBitmap* bitmapLoad;
wxBitmap* bitmapFFS;
+ wxBitmap* bitmapFFSPaused;
wxBitmap* bitmapDeleteFile;
wxBitmap* bitmapGPL;
wxBitmap* bitmapStatusPause;
diff --git a/library/sorting.h b/library/sorting.h
index fabdad1f..23c219b9 100644
--- a/library/sorting.h
+++ b/library/sorting.h
@@ -106,24 +106,34 @@ bool sortByFileName(const FileCompareLine& a, const FileCompareLine& b)
return false; //empty rows always last
else if (descrLineB->objType == FileDescrLine::TYPE_NOTHING)
return true; //empty rows always last
- else if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY)
- return false;
- else if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY)
- return true;
+
+
+ if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY) //sort directories by relative name
+ {
+ if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY)
+ return stringSmallerThan<sortAscending>(descrLineA->relativeName.c_str(), descrLineB->relativeName.c_str());
+ else
+ return false;
+ }
else
{
- const wxChar* stringA = descrLineA->relativeName.c_str();
- const wxChar* stringB = descrLineB->relativeName.c_str();
+ if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY)
+ return true;
+ else
+ {
+ const wxChar* stringA = descrLineA->relativeName.c_str();
+ const wxChar* stringB = descrLineB->relativeName.c_str();
- size_t pos = descrLineA->relativeName.Find(GlobalResources::FILE_NAME_SEPARATOR, true); //start search beginning from end
- if (pos != std::string::npos)
- stringA += pos + 1;
+ size_t pos = descrLineA->relativeName.Find(GlobalResources::FILE_NAME_SEPARATOR, true); //start search beginning from end
+ if (pos != std::string::npos)
+ stringA += pos + 1;
- pos = descrLineB->relativeName.Find(GlobalResources::FILE_NAME_SEPARATOR, true); //start search beginning from end
- if (pos != std::string::npos)
- stringB += pos + 1;
+ pos = descrLineB->relativeName.Find(GlobalResources::FILE_NAME_SEPARATOR, true); //start search beginning from end
+ if (pos != std::string::npos)
+ stringB += pos + 1;
- return stringSmallerThan<sortAscending>(stringA, stringB);
+ return stringSmallerThan<sortAscending>(stringA, stringB);
+ }
}
}
@@ -205,7 +215,7 @@ bool sortByRelativeName(const FileCompareLine& a, const FileCompareLine& b)
template <bool sortAscending, SideToSort side>
inline
-bool sortByFileSize(const FileCompareLine& a, const FileCompareLine& b)
+bool sortByFullName(const FileCompareLine& a, const FileCompareLine& b)
{
const FileDescrLine* descrLineA = NULL;
const FileDescrLine* descrLineB = NULL;
@@ -216,14 +226,50 @@ bool sortByFileSize(const FileCompareLine& a, const FileCompareLine& b)
return false; //empty rows always last
else if (descrLineB->objType == FileDescrLine::TYPE_NOTHING)
return true; //empty rows always last
- else if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY)
- return false;
- else if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY)
- return true;
else
+#ifdef FFS_WIN //case-insensitive comparison!
+ return sortAscending ?
+ FreeFileSync::compareStringsWin32(descrLineA->fullName.c_str(), descrLineB->fullName.c_str()) < 0 : //way faster than wxString::CmpNoCase() in windows build!!!
+ FreeFileSync::compareStringsWin32(descrLineA->fullName.c_str(), descrLineB->fullName.c_str()) > 0;
+#else
return sortAscending ?
- descrLineA->fileSize < descrLineB->fileSize :
- descrLineA->fileSize > descrLineB->fileSize;
+ descrLineA->fullName.Cmp(descrLineB->fullName) < 0 :
+ descrLineA->fullName.Cmp(descrLineB->fullName) > 0;
+#endif
+}
+
+
+template <bool sortAscending, SideToSort side>
+inline
+bool sortByFileSize(const FileCompareLine& a, const FileCompareLine& b)
+{
+ const FileDescrLine* descrLineA = NULL;
+ const FileDescrLine* descrLineB = NULL;
+ getDescrLine<side>(a, b, descrLineA, descrLineB);
+
+ //presort types: first files, then directories then empty rows
+ if (descrLineA->objType == FileDescrLine::TYPE_NOTHING)
+ return false; //empty rows always last
+ else if (descrLineB->objType == FileDescrLine::TYPE_NOTHING)
+ return true; //empty rows always last
+
+
+ if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY) //sort directories by relative name
+ {
+ if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY)
+ return stringSmallerThan<sortAscending>(descrLineA->relativeName.c_str(), descrLineB->relativeName.c_str());
+ else
+ return false;
+ }
+ else
+ {
+ if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY)
+ return true;
+ else
+ return sortAscending ?
+ descrLineA->fileSize > descrLineB->fileSize : //sortAscending == true shall result in list beginning with largest files first
+ descrLineA->fileSize < descrLineB->fileSize;
+ }
}
@@ -240,14 +286,23 @@ bool sortByDate(const FileCompareLine& a, const FileCompareLine& b)
return false; //empty rows always last
else if (descrLineB->objType == FileDescrLine::TYPE_NOTHING)
return true; //empty rows always last
- else if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY)
- return false;
- else if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY)
- return true;
+
+ if (descrLineA->objType == FileDescrLine::TYPE_DIRECTORY) //sort directories by relative name
+ {
+ if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY)
+ return stringSmallerThan<sortAscending>(descrLineA->relativeName.c_str(), descrLineB->relativeName.c_str());
+ else
+ return false;
+ }
else
- return sortAscending ?
- descrLineA->lastWriteTimeRaw < descrLineB->lastWriteTimeRaw :
- descrLineA->lastWriteTimeRaw > descrLineB->lastWriteTimeRaw;
+ {
+ if (descrLineB->objType == FileDescrLine::TYPE_DIRECTORY)
+ return true;
+ else
+ return sortAscending ?
+ descrLineA->lastWriteTimeRaw < descrLineB->lastWriteTimeRaw :
+ descrLineA->lastWriteTimeRaw > descrLineB->lastWriteTimeRaw;
+ }
}
diff --git a/library/statusHandler.h b/library/statusHandler.h
index bae1de8e..208a2df8 100644
--- a/library/statusHandler.h
+++ b/library/statusHandler.h
@@ -10,7 +10,7 @@ bool updateUiIsAllowed(); //test if a specific amount of time is over
void updateUiNow(); //do the updating
-//interfaces for status updates (can be implemented by UI or commandline)
+//interfaces for status updates (can be implemented by GUI or Batch mode)
//overwrite virtual methods for respective functionality
class ErrorHandler
@@ -24,15 +24,14 @@ public:
IGNORE_ERROR = 10,
RETRY
};
- virtual Response reportError(const Zstring& text) = 0;
+ virtual Response reportError(const Zstring& errorMessage) = 0;
};
class StatusHandler
{
public:
- StatusHandler() :
- abortRequested(false) {}
+ StatusHandler() : abortRequested(false) {}
virtual ~StatusHandler() {}
//identifiers of different processes
@@ -48,7 +47,6 @@ public:
virtual void updateStatusText(const Zstring& text) = 0;
virtual void initNewProcess(int objectsTotal, double dataTotal, Process processID) = 0; //informs about the total amount of data that will be processed from now on
virtual void updateProcessedData(int objectsProcessed, double dataProcessed) = 0; //called periodically after data was processed
- virtual ErrorHandler::Response reportError(const Zstring& text) = 0;
//this method is triggered repeatedly by requestUiRefresh() and can be used to refresh the ui by dispatching pending events
virtual void forceUiRefresh() = 0;
@@ -66,6 +64,11 @@ public:
abortRequested = true;
}
+ //error handling:
+ virtual ErrorHandler::Response reportError(const Zstring& errorMessage) = 0; //recoverable error situation
+ virtual void reportFatalError(const Zstring& errorMessage) = 0; //non-recoverable error situation, implement abort!
+ virtual void reportWarning(const Zstring& warningMessage, bool& dontShowAgain) = 0;
+
protected:
virtual void abortThisProcess() = 0;
diff --git a/library/zstring.cpp b/library/zstring.cpp
index 35704b01..27633392 100644
--- a/library/zstring.cpp
+++ b/library/zstring.cpp
@@ -24,29 +24,23 @@ void testZstringForMemoryLeak()
#ifdef FFS_WIN
-int FreeFileSync::compareStringsWin32(const wchar_t* a, const wchar_t* b)
-{
- return lstrcmpi(
- a, //address of first string
- b); //address of second string
-}
-
-
-//equivalent implementation, but slightly(!!!) slower:
int FreeFileSync::compareStringsWin32(const wchar_t* a, const wchar_t* b, const int aCount, const int bCount)
{
- int rv = CompareString(
- LOCALE_USER_DEFAULT, //locale identifier
- NORM_IGNORECASE, //comparison-style options
- a, //pointer to first string
- aCount, //size, in bytes or characters, of first string
- b, //pointer to second string
- bCount); //size, in bytes or characters, of second string
+ //DON'T use lstrcmpi() here! It uses word sort, which unfortunately is NOT always a strict weak sorting function for some locales (e.g. swedish)
+ //Use CompareString() with "SORT_STRINGSORT" instead!!!
+
+ const int rv = CompareString(
+ LOCALE_USER_DEFAULT, //locale identifier
+ NORM_IGNORECASE | SORT_STRINGSORT, //comparison-style options
+ a, //pointer to first string
+ aCount, //size, in bytes or characters, of first string
+ b, //pointer to second string
+ bCount); //size, in bytes or characters, of second string
if (rv == 0)
throw RuntimeException(wxString(wxT("Error comparing strings!")));
else
- return rv - 2;
+ return rv - 2; //convert to C-style string compare result
}
#endif
diff --git a/library/zstring.h b/library/zstring.h
index 9013dd22..60ba464c 100644
--- a/library/zstring.h
+++ b/library/zstring.h
@@ -14,8 +14,7 @@ namespace FreeFileSync
{
#ifdef FFS_WIN
//super fast case-insensitive string comparison: way faster than wxString::CmpNoCase()!!!
- int compareStringsWin32(const wchar_t* a, const wchar_t* b);
- int compareStringsWin32(const wchar_t* a, const wchar_t* b, const int aCount, const int bCount);
+ int compareStringsWin32(const wchar_t* a, const wchar_t* b, const int aCount = -1, const int bCount = -1);
#endif //FFS_WIN
}
@@ -322,11 +321,11 @@ void Zstring::incRef() const
inline
void Zstring::decRef()
{
- assert(descr && descr->refCount >= 1);
+ assert(descr && descr->refCount >= 1); //descr points to the begin of the allocated memory block
if (--descr->refCount == 0)
{
- assert(descr); //descr points to the begin of the allocated memory block
free(descr); //this must NEVER be changed!! E.g. Trim() relies on descr being start of allocated memory block
+ descr = 0;
#ifdef __WXDEBUG__
--allocCount; //test Zstring for memory leaks
#endif
@@ -345,7 +344,7 @@ int Zstring::CmpNoCase(const DefaultChar* other) const
inline
int Zstring::CmpNoCase(const Zstring& other) const
{
- return FreeFileSync::compareStringsWin32(c_str(), other.c_str()); //way faster than wxString::CmpNoCase()!!
+ return FreeFileSync::compareStringsWin32(c_str(), other.c_str(), length(), other.length()); //way faster than wxString::CmpNoCase()!!
}
#endif
bgstack15