diff options
Diffstat (limited to 'library')
-rw-r--r-- | library/CustomGrid.cpp | 879 | ||||
-rw-r--r-- | library/CustomGrid.h | 118 | ||||
-rw-r--r-- | library/customButton.cpp | 293 | ||||
-rw-r--r-- | library/customButton.h | 40 | ||||
-rw-r--r-- | library/fileHandling.cpp | 82 | ||||
-rw-r--r-- | library/fileHandling.h | 8 | ||||
-rw-r--r-- | library/globalFunctions.cpp | 20 | ||||
-rw-r--r-- | library/globalFunctions.h | 22 | ||||
-rw-r--r-- | library/misc.cpp | 32 | ||||
-rw-r--r-- | library/misc.h | 5 | ||||
-rw-r--r-- | library/multithreading.cpp | 1 | ||||
-rw-r--r-- | library/processXml.cpp | 320 | ||||
-rw-r--r-- | library/processXml.h | 79 | ||||
-rw-r--r-- | library/resources.cpp | 12 | ||||
-rw-r--r-- | library/resources.h | 9 | ||||
-rw-r--r-- | library/sorting.h | 21 | ||||
-rw-r--r-- | library/statusHandler.h | 8 | ||||
-rw-r--r-- | library/zstring.cpp | 68 | ||||
-rw-r--r-- | library/zstring.h | 197 |
19 files changed, 1581 insertions, 633 deletions
diff --git a/library/CustomGrid.cpp b/library/CustomGrid.cpp index 25ceb537..95300a2b 100644 --- a/library/CustomGrid.cpp +++ b/library/CustomGrid.cpp @@ -3,24 +3,28 @@ #include "resources.h" #include <wx/dc.h> #include "../algorithm.h" +#include "resources.h" + +using namespace xmlAccess; + -const unsigned int MinimumRows = 15; +const unsigned int MIN_ROW_COUNT = 15; //class containing pure grid data: basically the same as wxGridStringTable, but adds cell formatting -class CustomGridTableBase : public wxGridStringTable +class CustomGridTable : public wxGridTableBase { public: - CustomGridTableBase(int numRows, int numCols) : - wxGridStringTable(numRows, numCols), + CustomGridTable() : + wxGridTableBase(), lightBlue(80, 110, 255), lightGrey(212, 208, 200), - gridIdentifier(0), - gridRefUI(0), - gridData(0), - lastNrRows(MinimumRows) {} + gridRefUI(NULL), + gridData(NULL), + lastNrRows(0), + lastNrCols(0) {} - ~CustomGridTableBase() {} + virtual ~CustomGridTable() {} void setGridDataTable(GridView* gridRefUI, FileCompareResult* gridData) @@ -30,182 +34,56 @@ public: } - void SetGridIdentifier(int id) - { - gridIdentifier = id; - } - //########################################################################### //grid standard input output methods, redirected directly to gridData to improve performance virtual int GetNumberRows() { if (gridRefUI) - return max(gridRefUI->size(), MinimumRows); + return std::max(gridRefUI->size(), MIN_ROW_COUNT); else - return MinimumRows; //grid is initialized with this number of rows + return 0; //grid is initialized with zero number of rows } - virtual bool IsEmptyCell( int row, int col ) + virtual int GetNumberCols() //virtual used by middle grid! { - return (GetValue(row, col) == wxEmptyString); + return columnPositions.size(); } - wxString evaluateCmpResult(const CompareFilesResult result, const bool selectedForSynchronization) + virtual bool IsEmptyCell( int row, int col ) { - if (selectedForSynchronization) - switch (result) - { - case FILE_LEFT_SIDE_ONLY: - return wxT("<|"); - break; - case FILE_RIGHT_SIDE_ONLY: - return wxT("|>"); - break; - case FILE_RIGHT_NEWER: - return wxT(">>"); - break; - case FILE_LEFT_NEWER: - return wxT("<<"); - break; - case FILE_DIFFERENT: - return wxT("!="); - break; - case FILE_EQUAL: - return wxT("=="); - break; - default: - assert (false); - return wxEmptyString; - } - else return wxT("(-)"); + return (GetValue(row, col) == wxEmptyString); } - virtual wxString GetValue(int row, int col) - { - if (gridRefUI) - { - if (unsigned(row) < gridRefUI->size()) - { - const FileCompareLine& gridLine = (*gridData)[(*gridRefUI)[row]]; - wxString fileSize; //tmp string - - switch (gridIdentifier) - { - case 1: - if (col < 4) - { - if (gridLine.fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY) - { - switch (col) - { - case 0: //filename - return wxEmptyString; - case 1: //relative path - return gridLine.fileDescrLeft.relativeName; - case 2: //file size - return _("<Directory>"); - case 3: //date - return wxEmptyString; - } - } - else if (gridLine.fileDescrLeft.objType == FileDescrLine::TYPE_FILE) - { - switch (col) - { - case 0: //filename - return gridLine.fileDescrLeft.relativeName.AfterLast(GlobalResources::FILE_NAME_SEPARATOR); - case 1: //relative path - return gridLine.fileDescrLeft.relativeName.BeforeLast(GlobalResources::FILE_NAME_SEPARATOR); - case 2: //file size - return globalFunctions::includeNumberSeparator(fileSize = gridLine.fileDescrLeft.fileSize.ToString()); - case 3: //date - return FreeFileSync::utcTimeToLocalString(gridLine.fileDescrLeft.lastWriteTimeRaw); - } - } - } - else - assert (false); - - break; - - case 2: - if (col < 4) - { - if (gridLine.fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY) - { - switch (col) - { - case 0: //filename - return wxEmptyString; - case 1: //relative path - return gridLine.fileDescrRight.relativeName; - case 2: //file size - return _("<Directory>"); - case 3: //date - return wxEmptyString; - } - } - else if (gridLine.fileDescrRight.objType == FileDescrLine::TYPE_FILE) - { - switch (col) - { - case 0: //filename - return gridLine.fileDescrRight.relativeName.AfterLast(GlobalResources::FILE_NAME_SEPARATOR); - case 1: //relative path - return gridLine.fileDescrRight.relativeName.BeforeLast(GlobalResources::FILE_NAME_SEPARATOR); - case 2: //file size - return globalFunctions::includeNumberSeparator(fileSize = gridLine.fileDescrRight.fileSize.ToString()); - case 3: //date - return FreeFileSync::utcTimeToLocalString(gridLine.fileDescrRight.lastWriteTimeRaw); - } - } - } - else - assert (false); - - break; + virtual wxString GetValue(int row, int col) = 0; - case 3: - if (col < 1) - return evaluateCmpResult(gridLine.cmpResult, gridLine.selectedForSynchronization); - else - assert (false); - break; - default: - assert (false); - break; - } - } - } - //if data is not found: - return wxEmptyString; - } - - - virtual void SetValue( int row, int col, const wxString& value ) + virtual void SetValue(int row, int col, const wxString& value) { assert (false); //should not be used, since values are retrieved directly from gridRefUI } + virtual void Clear() { assert (false); // we don't want to use this, since the visible grid is directly connected to gridRefUI} } - virtual bool InsertRows( size_t pos = 0, size_t numRows = 1 ) + + virtual bool InsertRows(size_t pos = 0, size_t numRows = 1) { assert (false); // we don't want to use this, since the visible grid is directly connected to gridRefUI} return true; } - virtual bool AppendRows( size_t numRows = 1 ) + + virtual bool AppendRows(size_t numRows = 1) { assert (false); // we don't want to use this, since the visible grid is directly connected to gridRefUI} return true; } - virtual bool DeleteRows( size_t pos = 0, size_t numRows = 1 ) + + virtual bool DeleteRows(size_t pos = 0, size_t numRows = 1) { assert (false); // we don't want to use this, since the visible grid is directly connected to gridRefUI} return true; @@ -216,7 +94,7 @@ public: { if (gridRefUI) { - int currentNrRows = GetNumberRows(); + const int currentNrRows = GetNumberRows(); if (lastNrRows < currentNrRows) { @@ -243,79 +121,326 @@ public: } lastNrRows = currentNrRows; } - } -//########################################################################### - enum RowColor {BLUE, GREY, NONE}; + const int currentNrCols = GetNumberCols(); - inline //redundant command - RowColor getRowColor(int row) //rows that are filtered out are shown in different color - { - if (gridRefUI) + if (lastNrCols < currentNrCols) { - if (unsigned(row) < gridRefUI->size()) + if (GetView()) { - const FileCompareLine cmpLine = (*gridData)[(*gridRefUI)[row]]; - - //mark filtered rows - if (!cmpLine.selectedForSynchronization) - return BLUE; - //mark directories - else if (gridIdentifier == 1 && cmpLine.fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY) - return GREY; - else if (gridIdentifier == 2 && cmpLine.fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY) - return GREY; - else - return NONE; + wxGridTableMessage msg(this, + wxGRIDTABLE_NOTIFY_COLS_APPENDED, + currentNrCols - lastNrCols); + + GetView()->ProcessTableMessage( msg ); } } - return NONE; + else if (lastNrCols > currentNrCols) + { + if (GetView()) + { + wxGridTableMessage msg(this, + wxGRIDTABLE_NOTIFY_COLS_DELETED, + 0, + lastNrCols - currentNrCols); + + GetView()->ProcessTableMessage( msg ); + } + } + lastNrCols = currentNrCols; } +//########################################################################### - wxGridCellAttr* GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind) + virtual wxString GetColLabelValue( int col ) { - wxGridCellAttr* result = wxGridTableBase::GetAttr(row, col, kind); + return CustomGrid::getTypeName(getTypeAtPos(col)); + } + + + virtual wxGridCellAttr* GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind) + { + const wxColour& color = getRowColor(row); - // MARK FILTERED ROWS: + //add color to some rows + wxGridCellAttr* result = wxGridTableBase::GetAttr(row, col, kind); if (result) - { //if kind is not a cell or row attribute, we have to clone the cell attribute, since we don't want to change e.g. all column attribs - if (result->GetKind() != wxGridCellAttr::Cell && result->GetKind() != wxGridCellAttr::Row) + { + if (result->GetBackgroundColour() == color) { - wxGridCellAttr* attr = result->Clone(); + return result; + } + else //grid attribute might be referenced by other nodes, so clone it! + { + wxGridCellAttr* attr = result->Clone(); //attr has ref-count 1 result->DecRef(); result = attr; } - - RowColor color = getRowColor(row); - if (color == BLUE) - result->SetBackgroundColour(lightBlue); - else if (color == GREY) - result->SetBackgroundColour(lightGrey); - else - result->SetBackgroundColour(*wxWHITE); } else - { - result = new wxGridCellAttr; + result = new wxGridCellAttr; //created with ref-count 1 - RowColor color = getRowColor(row); - if (color == BLUE) - result->SetBackgroundColour(lightBlue); - else if (color == GREY) - result->SetBackgroundColour(lightGrey); - } + result->SetBackgroundColour(color); return result; } -private: + + void setupColumns(const std::vector<xmlAccess::XmlGlobalSettings::ColumnTypes>& positions) + { + columnPositions = positions; + updateGridSizes(); //add or remove columns + } + + + XmlGlobalSettings::ColumnTypes getTypeAtPos(unsigned pos) const + { + if (pos < columnPositions.size()) + return columnPositions[pos]; + else + return XmlGlobalSettings::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; + wxColour lightBlue; wxColour lightGrey; - int gridIdentifier; GridView* gridRefUI; //(very fast) access to underlying grid data :) FileCompareResult* gridData; int lastNrRows; + int lastNrCols; +}; + + +class CustomGridTableLeft : public CustomGridTable +{ +public: + CustomGridTableLeft() : CustomGridTable() {} + ~CustomGridTableLeft() {} + + virtual const wxColour& getRowColor(int row) //rows that are filtered out are shown in different color + { + if (gridRefUI && unsigned(row) < gridRefUI->size()) + { + const FileCompareLine cmpLine = (*gridData)[(*gridRefUI)[row]]; + + //mark filtered rows + if (!cmpLine.selectedForSynchronization) + return lightBlue; + //mark directories + else if (cmpLine.fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY) + return lightGrey; + else + return *wxWHITE; + } + return *wxWHITE; + } + + + //virtual impl. + wxString GetValue(int row, int col) + { + if (gridRefUI) + { + if (unsigned(row) < gridRefUI->size()) + { + const FileCompareLine& gridLine = (*gridData)[(*gridRefUI)[row]]; + + if (gridLine.fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY) + { + switch (getTypeAtPos(col)) + { + case XmlGlobalSettings::FILENAME: //filename + return wxEmptyString; + case XmlGlobalSettings::REL_PATH: //relative path + return gridLine.fileDescrLeft.relativeName.c_str(); + case XmlGlobalSettings::SIZE: //file size + return _("<Directory>"); + case XmlGlobalSettings::DATE: //date + return wxEmptyString; + } + } + else if (gridLine.fileDescrLeft.objType == FileDescrLine::TYPE_FILE) + { + switch (getTypeAtPos(col)) + { + case XmlGlobalSettings::FILENAME: //filename + return gridLine.fileDescrLeft.relativeName.AfterLast(GlobalResources::FILE_NAME_SEPARATOR).c_str(); + case XmlGlobalSettings::REL_PATH: //relative path + return gridLine.fileDescrLeft.relativeName.BeforeLast(GlobalResources::FILE_NAME_SEPARATOR).c_str(); + case XmlGlobalSettings::SIZE: //file size + { + wxString fileSize = gridLine.fileDescrLeft.fileSize.ToString(); //tmp string + return globalFunctions::includeNumberSeparator(fileSize); + } + case XmlGlobalSettings::DATE: //date + return FreeFileSync::utcTimeToLocalString(gridLine.fileDescrLeft.lastWriteTimeRaw); + } + } + } + } + //if data is not found: + return wxEmptyString; + } +}; + + +class CustomGridTableMiddle : public CustomGridTable +{ +public: + CustomGridTableMiddle() : CustomGridTable() + { + lastNrCols = 1; //ensure CustomGridTable::updateGridSizes() is working correctly + } + ~CustomGridTableMiddle() {} + + //virtual impl. + int GetNumberCols() + { + return 1; + } + + + int selectedForSynchronization(const unsigned int row) // 0 == false, 1 == true, -1 == not defined + { + if (gridRefUI && row < gridRefUI->size()) + { + const FileCompareLine cmpLine = (*gridData)[(*gridRefUI)[row]]; + + if (cmpLine.selectedForSynchronization) + return 1; + else + return 0; + } + return -1; + } + + + //virtual impl. + const wxColour& getRowColor(int row) //rows that are filtered out are shown in different color + { + if (gridRefUI && unsigned(row) < gridRefUI->size()) + { + const FileCompareLine cmpLine = (*gridData)[(*gridRefUI)[row]]; + + //mark filtered rows + if (!cmpLine.selectedForSynchronization) + return lightBlue; + else + return *wxWHITE; + } + return *wxWHITE; + } + + //virtual impl. + wxString GetValue(int row, int col) + { + if (gridRefUI) + { + if (unsigned(row) < gridRefUI->size()) + { + const FileCompareLine& gridLine = (*gridData)[(*gridRefUI)[row]]; + + switch (gridLine.cmpResult) + { + case FILE_LEFT_SIDE_ONLY: + return wxT("<|"); + case FILE_RIGHT_SIDE_ONLY: + return wxT("|>"); + case FILE_RIGHT_NEWER: + return wxT(">>"); + case FILE_LEFT_NEWER: + return wxT("<<"); + case FILE_DIFFERENT: + return wxT("!="); + case FILE_EQUAL: + return wxT("=="); + default: + assert (false); + return wxEmptyString; + } + } + } + //if data is not found: + return wxEmptyString; + } +}; + + +class CustomGridTableRight : public CustomGridTable +{ +public: + CustomGridTableRight() : CustomGridTable() {} + ~CustomGridTableRight() {} + + //virtual impl. + const wxColour& getRowColor(int row) //rows that are filtered out are shown in different color + { + if (gridRefUI && unsigned(row) < gridRefUI->size()) + { + const FileCompareLine cmpLine = (*gridData)[(*gridRefUI)[row]]; + + //mark filtered rows + if (!cmpLine.selectedForSynchronization) + return lightBlue; + //mark directories + else if (cmpLine.fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY) + return lightGrey; + else + return *wxWHITE; + } + return *wxWHITE; + } + + //virtual impl. + wxString GetValue(int row, int col) + { + if (gridRefUI) + { + if (unsigned(row) < gridRefUI->size()) + { + const FileCompareLine& gridLine = (*gridData)[(*gridRefUI)[row]]; + + if (gridLine.fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY) + { + switch (getTypeAtPos(col)) + { + case XmlGlobalSettings::FILENAME: //filename + return wxEmptyString; + case XmlGlobalSettings::REL_PATH: //relative path + return gridLine.fileDescrRight.relativeName.c_str(); + case XmlGlobalSettings::SIZE: //file size + return _("<Directory>"); + case XmlGlobalSettings::DATE: //date + return wxEmptyString; + } + } + else if (gridLine.fileDescrRight.objType == FileDescrLine::TYPE_FILE) + { + switch (getTypeAtPos(col)) + { + case XmlGlobalSettings::FILENAME: //filename + return gridLine.fileDescrRight.relativeName.AfterLast(GlobalResources::FILE_NAME_SEPARATOR).c_str(); + case XmlGlobalSettings::REL_PATH: //relative path + return gridLine.fileDescrRight.relativeName.BeforeLast(GlobalResources::FILE_NAME_SEPARATOR).c_str(); + case XmlGlobalSettings::SIZE: //file size + { + wxString fileSize = gridLine.fileDescrRight.fileSize.ToString(); //tmp string + return globalFunctions::includeNumberSeparator(fileSize); + } + case XmlGlobalSettings::DATE: //date + return FreeFileSync::utcTimeToLocalString(gridLine.fileDescrRight.lastWriteTimeRaw); + } + } + } + } + //if data is not found: + return wxEmptyString; + } }; @@ -333,26 +458,33 @@ CustomGrid::CustomGrid(wxWindow *parent, m_gridLeft(NULL), m_gridRight(NULL), m_gridMiddle(NULL), gridDataTable(NULL), currentSortColumn(-1), - sortMarker(NULL) {} - - -CustomGrid::~CustomGrid() {} - - -bool CustomGrid::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode) + sortMarker(NULL) { - //use custom wxGridTableBase class for management of large sets of formatted data. - //This is done in CreateGrid instead of SetTable method since source code is generated and wxFormbuilder invokes CreatedGrid by default. - - gridDataTable = new CustomGridTableBase(numRows, numCols); - SetTable(gridDataTable, true, selmode); //give ownership to wxGrid: gridDataTable is deleted automatically in wxGrid destructor - return true; + //set color of selections + wxColour darkBlue(40, 35, 140); + SetSelectionBackground(darkBlue); + SetSelectionForeground(*wxWHITE); } -void CustomGrid::deactivateScrollbars() +void CustomGrid::initSettings(bool enableScrollbars, + CustomGrid* gridLeft, + CustomGrid* gridRight, + CustomGrid* gridMiddle, + GridView* gridRefUI, + FileCompareResult* gridData) { - scrollbarsEnabled = false; + scrollbarsEnabled = enableScrollbars; + + //these grids will scroll together + assert(gridLeft && gridRight && gridMiddle); + m_gridLeft = gridLeft; + m_gridRight = gridRight; + m_gridMiddle = gridMiddle; + + //set underlying grid data + assert(gridDataTable); + gridDataTable->setGridDataTable(gridRefUI, gridData); } @@ -380,7 +512,7 @@ void CustomGrid::adjustGridHeights() //m_gridLeft, m_gridRight, m_gridMiddle are if (y1 != y2 || y2 != y3) { - int yMax = max(y1, max(y2, y3)); + int yMax = std::max(y1, std::max(y2, y3)); if (::leadGrid == m_gridLeft) //do not handle case (y1 == yMax) here!!! Avoid back coupling! m_gridLeft->SetMargins(0, 0); @@ -404,90 +536,311 @@ void CustomGrid::adjustGridHeights() //m_gridLeft, m_gridRight, m_gridMiddle are } -//this method is called when grid view changes: useful for parallel updating of multiple grids -void CustomGrid::DoPrepareDC(wxDC& dc) +void CustomGrid::updateGridSizes() { - wxScrollHelper::DoPrepareDC(dc); + assert(gridDataTable); + gridDataTable->updateGridSizes(); +} - int x, y = 0; - if (this == ::leadGrid) //avoid back coupling - { - if (this == m_gridLeft) + +void CustomGrid::setSortMarker(const int sortColumn, const wxBitmap* bitmap) +{ + currentSortColumn = sortColumn; + sortMarker = bitmap; +} + + +void CustomGrid::DrawColLabel(wxDC& dc, int col) +{ + wxGrid::DrawColLabel(dc, col); + + if (col == currentSortColumn) + dc.DrawBitmap(*sortMarker, GetColRight(col) - 16 - 2, 2, true); //respect 2-pixel border +} + + +void CustomGrid::setColumnAttributes(const xmlAccess::XmlGlobalSettings::ColumnAttributes& attr) +{ + //remove special alignment for column "size" + for (int i = 0; i < GetNumberCols(); ++i) + if (getTypeAtPos(i) == XmlGlobalSettings::SIZE) { - GetViewStart(&x, &y); - m_gridRight->Scroll(x, y); - m_gridMiddle->Scroll(-1, y); //scroll in y-direction only - adjustGridHeights(); //keep here to ensure m_gridLeft, m_gridRight, m_gridMiddle != NULL + wxGridCellAttr* cellAttributes = GetOrCreateCellAttr(0, i); + cellAttributes->SetAlignment(wxALIGN_LEFT,wxALIGN_CENTRE); + SetColAttr(i, cellAttributes); + break; } - else if (this == m_gridRight) +//---------------------------------------------------------------------------------- + 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); + } + else + { + for (unsigned int i = 0; i < COLUMN_TYPE_COUNT; ++i) { - GetViewStart(&x, &y); - m_gridLeft->Scroll(x, y); - m_gridMiddle->Scroll(-1, y); - adjustGridHeights(); //keep here to ensure m_gridLeft, m_gridRight, m_gridMiddle != NULL + XmlGlobalSettings::ColumnAttrib newEntry; + + if (i < attr.size()) + newEntry = attr[i]; + else + { + newEntry.type = xmlAccess::XmlGlobalSettings::FILENAME; + newEntry.visible = true; + newEntry.position = i; + newEntry.width = 100; + } + columnSettings.push_back(newEntry); } - else if (this == m_gridMiddle) + + 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); + + 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 + columnSettings[i].position = i; + + sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByPositionAndVisibility); + } + + std::vector<XmlGlobalSettings::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); + + //set column positions + assert(gridDataTable); + gridDataTable->setupColumns(newPositions); + + //set column width (set them after setupColumns!) + for (unsigned int i = 0; i < newPositions.size(); ++i) + SetColSize(i, columnSettings[i].width); + +//-------------------------------------------------------------------------------------------------------- + //set special alignment for column "size" + for (int i = 0; i < GetNumberCols(); ++i) + if (getTypeAtPos(i) == XmlGlobalSettings::SIZE) { - GetViewStart(&x, &y); - m_gridLeft->Scroll(-1, y); - m_gridRight->Scroll(-1, y); - adjustGridHeights(); //keep here to ensure m_gridLeft, m_gridRight, m_gridMiddle != NULL + wxGridCellAttr* cellAttributes = GetOrCreateCellAttr(0, i); + cellAttributes->SetAlignment(wxALIGN_RIGHT,wxALIGN_CENTRE); + SetColAttr(i, cellAttributes); //make filesize right justified on grids + break; } - } + + ClearSelection(); + ForceRefresh(); } -//these classes will scroll together, hence the name ;) -void CustomGrid::setScrollFriends(CustomGrid* gridLeft, CustomGrid* gridRight, CustomGrid* gridMiddle) +xmlAccess::XmlGlobalSettings::ColumnAttributes CustomGrid::getColumnAttributes() { - assert(gridLeft && gridRight && gridMiddle); + sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByPositionAndVisibility); - m_gridLeft = gridLeft; - m_gridRight = gridRight; - m_gridMiddle = gridMiddle; + 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); + } - assert(gridDataTable); - if (this == m_gridLeft) - gridDataTable->SetGridIdentifier(1); - else if (this == m_gridRight) - gridDataTable->SetGridIdentifier(2); - else if (this == m_gridMiddle) - gridDataTable->SetGridIdentifier(3); - else - assert (false); + return output; } -void CustomGrid::setGridDataTable(GridView* gridRefUI, FileCompareResult* gridData) -{ //set underlying grid data +XmlGlobalSettings::ColumnTypes CustomGrid::getTypeAtPos(unsigned pos) const +{ assert(gridDataTable); - gridDataTable->setGridDataTable(gridRefUI, gridData); + return gridDataTable->getTypeAtPos(pos); } -void CustomGrid::updateGridSizes() +wxString CustomGrid::getTypeName(XmlGlobalSettings::ColumnTypes colType) { - assert(gridDataTable); - gridDataTable->updateGridSizes(); + switch (colType) + { + case XmlGlobalSettings::FILENAME: + return _("Filename"); + case XmlGlobalSettings::REL_PATH: + return _("Relative path"); + case XmlGlobalSettings::SIZE: + return _("Size"); + case XmlGlobalSettings::DATE: + return _("Date"); + default: + return wxEmptyString; + } } +//############################################################################################ +//CustomGrid specializations -void CustomGrid::setSortMarker(const int sortColumn, const wxBitmap* bitmap) +CustomGridLeft::CustomGridLeft(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) : + CustomGrid(parent, id, pos, size, style, name) {} + + +bool CustomGridLeft::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode) { - currentSortColumn = sortColumn; - sortMarker = bitmap; + //use custom wxGridTableBase class for management of large sets of formatted data. + //This is done in CreateGrid instead of SetTable method since source code is generated and wxFormbuilder invokes CreatedGrid by default. + gridDataTable = new CustomGridTableLeft(); + SetTable(gridDataTable, true, wxGrid::wxGridSelectRows); //give ownership to wxGrid: gridDataTable is deleted automatically in wxGrid destructor + return true; } -void CustomGrid::DrawColLabel(wxDC& dc, int col) +//this method is called when grid view changes: useful for parallel updating of multiple grids +void CustomGridLeft::DoPrepareDC(wxDC& dc) { - assert(0 <= col && col < 4); + wxScrollHelper::DoPrepareDC(dc); - wxGrid::DrawColLabel(dc, col); + int x, y = 0; + if (this == ::leadGrid) //avoid back coupling + { + GetViewStart(&x, &y); + m_gridMiddle->Scroll(-1, y); //scroll in y-direction only + m_gridRight->Scroll(x, y); + adjustGridHeights(); //keep here to ensure m_gridLeft, m_gridRight, m_gridMiddle != NULL + } +} - if (col == currentSortColumn) + +//---------------------------------------------------------------------------------------- +CustomGridMiddle::CustomGridMiddle(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) : + CustomGrid(parent, id, pos, size, style, name) {} + + +bool CustomGridMiddle::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode) +{ + CustomGridTableMiddle* newTable = new CustomGridTableMiddle(); + gridDataTable = newTable; + SetTable(gridDataTable, true, wxGrid::wxGridSelectRows); //give ownership to wxGrid: gridDataTable is deleted automatically in wxGrid destructor + + //display checkboxes (representing bool values) if row is enabled for synchronization + SetDefaultRenderer(new GridCellRendererAddCheckbox(newTable)); //SetDefaultRenderer takes ownership! + + return true; +} + + +//this method is called when grid view changes: useful for parallel updating of multiple grids +void CustomGridMiddle::DoPrepareDC(wxDC& dc) +{ + wxScrollHelper::DoPrepareDC(dc); + + int x, y = 0; + if (this == ::leadGrid) //avoid back coupling { - dc.DrawBitmap(*sortMarker, GetColRight(col) - 16 - 2, 2, true); //respect 2-pixel border + GetViewStart(&x, &y); + m_gridLeft->Scroll(-1, y); + m_gridRight->Scroll(-1, y); + adjustGridHeights(); //keep here to ensure m_gridLeft, m_gridRight, m_gridMiddle != NULL } } + +void CustomGridMiddle::GridCellRendererAddCheckbox::Draw(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + const wxRect& rect, + int row, int col, + bool isSelected) +{ + const int selected = m_gridDataTable->selectedForSynchronization(row); + if (selected < 0) //no valid row + { + wxGridCellStringRenderer::Draw(grid, attr, dc, rect, row, col, isSelected); + return; + } + + const int shift = std::min(11 + 3, rect.GetWidth()); //11 is width of checkbox image + + wxRect rectShrinked(rect); + + //clean first block of rect that will receive image of checkbox + rectShrinked.SetWidth(shift); + dc.SetPen(*wxWHITE_PEN); + dc.SetBrush(*wxWHITE_BRUSH); + dc.DrawRectangle(rectShrinked); + + //print image into first block + rectShrinked.SetX(1); + if (selected > 0) + dc.DrawLabel(wxEmptyString, *globalResource.bitmapCheckBoxTrue, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + else //if (selected == 0) -> redundant + dc.DrawLabel(wxEmptyString, *globalResource.bitmapCheckBoxFalse, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + + //print second block (default): display compare result + rectShrinked.SetWidth(rect.GetWidth() - shift); + rectShrinked.SetX(shift); + wxGridCellStringRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected); +} + + +//---------------------------------------------------------------------------------------- +CustomGridRight::CustomGridRight(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) : + CustomGrid(parent, id, pos, size, style, name) {} + + +bool CustomGridRight::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode) +{ + gridDataTable = new CustomGridTableRight(); + SetTable(gridDataTable, true, wxGrid::wxGridSelectRows); //give ownership to wxGrid: gridDataTable is deleted automatically in wxGrid destructor + return true; +} + + +//this method is called when grid view changes: useful for parallel updating of multiple grids +void CustomGridRight::DoPrepareDC(wxDC& dc) +{ + wxScrollHelper::DoPrepareDC(dc); + + int x, y = 0; + if (this == ::leadGrid) //avoid back coupling + { + GetViewStart(&x, &y); + m_gridLeft->Scroll(x, y); + m_gridMiddle->Scroll(-1, y); + adjustGridHeights(); //keep here to ensure m_gridLeft, m_gridRight, m_gridMiddle != NULL + } +} diff --git a/library/CustomGrid.h b/library/CustomGrid.h index bd2f3fa8..97642159 100644 --- a/library/CustomGrid.h +++ b/library/CustomGrid.h @@ -4,12 +4,13 @@ #include <vector> #include <wx/grid.h> #include "../FreeFileSync.h" +#include "processXml.h" using namespace FreeFileSync; -class CustomGridTableBase; - +class CustomGridTable; +class CustomGridTableMiddle; //################################################################################## extern const wxGrid* leadGrid; //this global variable is not very nice... @@ -24,35 +25,128 @@ public: long style = wxWANTS_CHARS, const wxString& name = wxGridNameStr); - ~CustomGrid(); + virtual ~CustomGrid() {} - virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells); //overwrite virtual method to finally get rid of the scrollbars virtual void SetScrollbar(int orientation, int position, int thumbSize, int range, bool refresh = true); - //this method is called when grid view changes: useful for parallel updating of multiple grids - virtual void DoPrepareDC(wxDC& dc); + virtual void DrawColLabel(wxDC& dc, int col); - void deactivateScrollbars(); - void setScrollFriends(CustomGrid* gridLeft, CustomGrid* gridRight, CustomGrid* gridMiddle); - void setGridDataTable(GridView* gridRefUI, FileCompareResult* gridData); + void initSettings(bool enableScrollbars, + CustomGrid* gridLeft, + CustomGrid* gridRight, + CustomGrid* gridMiddle, + GridView* gridRefUI, + FileCompareResult* gridData); + + //notify wxGrid that underlying table size has changed void updateGridSizes(); + //set sort direction indicator on UI void setSortMarker(const int sortColumn, const wxBitmap* bitmap = &wxNullBitmap); -private: + //set visibility, position and width of columns + void setColumnAttributes(const xmlAccess::XmlGlobalSettings::ColumnAttributes& attr); + xmlAccess::XmlGlobalSettings::ColumnAttributes getColumnAttributes(); + + xmlAccess::XmlGlobalSettings::ColumnTypes getTypeAtPos(unsigned pos) const; + + static wxString getTypeName(xmlAccess::XmlGlobalSettings::ColumnTypes colType); + + static const unsigned COLUMN_TYPE_COUNT = 4; + +protected: + //set visibility, position and width of columns + xmlAccess::XmlGlobalSettings::ColumnAttributes columnSettings; + + void adjustGridHeights(); bool scrollbarsEnabled; - CustomGrid* m_gridLeft; CustomGrid* m_gridRight; CustomGrid* m_gridMiddle; - CustomGridTableBase* gridDataTable; + CustomGridTable* gridDataTable; int currentSortColumn; const wxBitmap* sortMarker; }; + +class CustomGridLeft : public CustomGrid +{ +public: + CustomGridLeft(wxWindow *parent, + wxWindowID id, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxWANTS_CHARS, + const wxString& name = wxGridNameStr); + + ~CustomGridLeft() {} + + //this method is called when grid view changes: useful for parallel updating of multiple grids + virtual void DoPrepareDC(wxDC& dc); + + virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells); +}; + + +class CustomGridMiddle : public CustomGrid +{ +public: + CustomGridMiddle(wxWindow *parent, + wxWindowID id, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxWANTS_CHARS, + const wxString& name = wxGridNameStr); + + ~CustomGridMiddle() {} + + //this method is called when grid view changes: useful for parallel updating of multiple grids + virtual void DoPrepareDC(wxDC& dc); + + virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells); + +private: + + class GridCellRendererAddCheckbox : public wxGridCellStringRenderer + { + public: + GridCellRendererAddCheckbox(CustomGridTableMiddle* gridDataTable) : m_gridDataTable(gridDataTable) {}; + + + virtual void Draw(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + const wxRect& rect, + int row, int col, + bool isSelected); + + private: + CustomGridTableMiddle* m_gridDataTable; + }; +}; + + +class CustomGridRight : public CustomGrid +{ +public: + CustomGridRight(wxWindow *parent, + wxWindowID id, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxWANTS_CHARS, + const wxString& name = wxGridNameStr); + + ~CustomGridRight() {} + + //this method is called when grid view changes: useful for parallel updating of multiple grids + virtual void DoPrepareDC(wxDC& dc); + + virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells); +}; + #endif // CUSTOMGRID_H_INCLUDED diff --git a/library/customButton.cpp b/library/customButton.cpp new file mode 100644 index 00000000..5cfa8a5a --- /dev/null +++ b/library/customButton.cpp @@ -0,0 +1,293 @@ +#include "customButton.h" +#include <wx/dcmemory.h> +#include <wx/image.h> + +wxButtonWithImage::wxButtonWithImage(wxWindow *parent, + wxWindowID id, + const wxString& label, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) : + wxBitmapButton(parent, id, wxNullBitmap, pos, size, style | wxBU_AUTODRAW, validator, name) +{ + setTextLabel(label); +} + + +void wxButtonWithImage::setBitmapFront(const wxBitmap& bitmap) +{ + bitmapFront = bitmap; + refreshButtonLabel(); +} + + +void wxButtonWithImage::setTextLabel(const wxString& text) +{ + textLabel = text; + wxBitmapButton::SetLabel(text); + refreshButtonLabel(); +} + + +void wxButtonWithImage::setBitmapBack(const wxBitmap& bitmap) +{ + bitmapBack = bitmap; + refreshButtonLabel(); +} + + +void makeWhiteTransparent(const wxColor exceptColor, wxImage& image) +{ + unsigned char* alphaData = image.GetAlpha(); + if (alphaData) + { + assert(exceptColor.Red() != 255); + + unsigned char exCol = exceptColor.Red(); //alpha value can be extracted from any one of (red/green/blue) + unsigned char* imageStart = image.GetData(); + + unsigned char* j = alphaData; + const unsigned char* const rowEnd = j + image.GetWidth() * image.GetHeight(); + while (j != rowEnd) + { + const unsigned char* imagePixel = imageStart + (j - alphaData) * 3; //each pixel consists of three chars + //exceptColor(red,green,blue) becomes fully opaque(255), while white(255,255,255) becomes transparent(0) + *(j++) = ((255 - imagePixel[0]) * wxIMAGE_ALPHA_OPAQUE) / (255 - exCol); + } + } +} + + +wxSize getSizeNeeded(const wxString& text, wxFont& font) +{ + wxCoord width, height; + wxMemoryDC dc; + + wxString textFormatted = text; + textFormatted.Replace(wxT("&"), wxT(""), false); //remove accelerator + dc.GetMultiLineTextExtent(textFormatted, &width, &height , NULL, &font); + return wxSize(width, height); +} + +/* +inline +void linearInterpolationHelper(const int shift, wxImage& img) +{ + unsigned char* const data = img.GetData(); + const int width = img.GetWidth(); + if (width < 2) + return; + + const float intensity = 0.25; + + for (int y = 1; y < img.GetHeight() - 1; ++y) + { + float back = 0; + float middle = 0; + float front = 0; + + unsigned char* location = data + 3 * (y * width) + shift; + const unsigned char* const endPos = location + 3 * width; + + middle = (*location + *(location - 3 * width) + *(location + 3 * width)) / 3;; + front = (*(location + 3) + *(location + 3 * (1 - width)) + *(location + 3 * (1 + width))) / 3; + *location += ((middle + front) / 2 - *location) * intensity; + location += 3; + + while (location < endPos - 3) + { + back = middle; + middle = front; + front = (*(location + 3) + *(location + 3 * (1 - width)) + *(location + 3 * (1 + width))) / 3; + *location += ((back + middle + front) / 3 - *location) * intensity; + location += 3; + } + + back = middle; + middle = front; + *location += ((back + middle) / 2 - *location) * intensity; + } +} + + +void linearInterpolation(wxImage& img) +{ + linearInterpolationHelper(0, img); //red channel + linearInterpolationHelper(1, img); //green channel + linearInterpolationHelper(2, img); //blue channel +} +*/ + +wxBitmap wxButtonWithImage::createBitmapFromText(const wxString& text) +{ + wxFont currentFont = wxBitmapButton::GetFont(); + wxColor textColor = wxBitmapButton::GetForegroundColour(); + + wxSize sizeNeeded = getSizeNeeded(text, currentFont); + wxBitmap newBitmap(sizeNeeded.GetWidth(), sizeNeeded.GetHeight()); + + wxMemoryDC dc; + dc.SelectObject(newBitmap); + + //set up white background + dc.SetBackground(*wxWHITE_BRUSH); + dc.Clear(); + + //find position of accelerator + int indexAccel = -1; + size_t accelPos; + wxString textLabelFormatted = text; + if ((accelPos = text.find(wxT("&"))) != wxString::npos) + { + textLabelFormatted.Replace(wxT("&"), wxT(""), false); //remove accelerator + indexAccel = accelPos; + } + + dc.SetTextForeground(textColor); + dc.SetTextBackground(*wxWHITE); + dc.SetFont(currentFont); + dc.DrawLabel(textLabelFormatted, wxNullBitmap, wxRect(0, 0, newBitmap.GetWidth(), newBitmap.GetHeight()), wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL, indexAccel); + + dc.SelectObject(wxNullBitmap); + + //add alpha channel to image + wxImage finalImage(newBitmap.ConvertToImage()); + finalImage.SetAlpha(); + + //linearInterpolation(finalImage); + + //make white background transparent + makeWhiteTransparent(textColor, finalImage); + + return wxBitmap(finalImage); +} + + +//copy one image into another, allowing arbitrary overlapping! (pos may contain negative numbers) +void writeToImage(const wxImage& source, const wxPoint pos, wxImage& target) +{ + //determine startpositions in source and target image, as well as width and height to be copied + wxPoint posSrc, posTrg; + int width, height; + + //X-axis + if (pos.x < 0) + { + posSrc.x = -pos.x; + posTrg.x = 0; + width = std::min(pos.x + source.GetWidth(), target.GetWidth()); + } + else + { + posSrc.x = 0; + posTrg.x = pos.x; + width = std::min(target.GetWidth() - pos.x, source.GetWidth()); + } + + //Y-axis + if (pos.y < 0) + { + posSrc.y = -pos.y; + posTrg.y = 0; + height = std::min(pos.y + source.GetHeight(), target.GetHeight()); + } + else + { + posSrc.y = 0; + posTrg.y = pos.y; + height = std::min(target.GetHeight() - pos.y, source.GetHeight()); + } + + + if (width > 0 && height > 0) + { + //copy source to target respecting overlapping parts + const unsigned char* sourcePtr = source.GetData() + 3 * (posSrc.x + posSrc.y * source.GetWidth()); + const unsigned char* const sourcePtrEnd = source.GetData() + 3 * (posSrc.x + (posSrc.y + height) * source.GetWidth()); + unsigned char* targetPtr = target.GetData() + 3 * (posTrg.x + posTrg.y * target.GetWidth()); + + while (sourcePtr < sourcePtrEnd) + { + memcpy(targetPtr, sourcePtr, 3 * width); + sourcePtr += 3 * source.GetWidth(); + targetPtr += 3 * target.GetWidth(); + } + + //handle different cases concerning alpha channel + if (source.HasAlpha()) + { + if (!target.HasAlpha()) + { + target.SetAlpha(); + unsigned char* alpha = target.GetAlpha(); + memset(alpha, wxIMAGE_ALPHA_OPAQUE, target.GetWidth() * target.GetHeight()); + } + + //copy alpha channel + const unsigned char* sourcePtr = source.GetAlpha() + (posSrc.x + posSrc.y * source.GetWidth()); + const unsigned char* const sourcePtrEnd = source.GetAlpha() + (posSrc.x + (posSrc.y + height) * source.GetWidth()); + unsigned char* targetPtr = target.GetAlpha() + (posTrg.x + posTrg.y * target.GetWidth()); + + while (sourcePtr < sourcePtrEnd) + { + memcpy(targetPtr, sourcePtr, width); + sourcePtr += source.GetWidth(); + targetPtr += target.GetWidth(); + } + } + else if (target.HasAlpha()) + { + unsigned char* targetPtr = target.GetAlpha() + (posTrg.x + posTrg.y * target.GetWidth()); + const unsigned char* const targetPtrEnd = target.GetAlpha() + (posTrg.x + (posTrg.y + height) * target.GetWidth()); + + while (targetPtr < targetPtrEnd) + { + memset(targetPtr, wxIMAGE_ALPHA_OPAQUE, width); + targetPtr += target.GetWidth(); + } + } + } +} + + +void wxButtonWithImage::refreshButtonLabel() +{ + wxBitmap bitmapText = createBitmapFromText(textLabel); + + //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(); + + //create a transparent image + wxImage transparentImage(width, height, false); + transparentImage.SetAlpha(); + unsigned char* alpha = transparentImage.GetAlpha(); + memset(alpha, wxIMAGE_ALPHA_TRANSPARENT, width * height); + + //wxDC::DrawLabel() unfortunately isn't working for transparent images on Linux, so we need to use custom image-concatenation + if (bitmapFront.IsOk()) + writeToImage(wxImage(bitmapFront.ConvertToImage()), + wxPoint(0, (transparentImage.GetHeight() - bitmapFront.GetHeight()) / 2), + transparentImage); + + if (bitmapText.IsOk()) + writeToImage(wxImage(bitmapText.ConvertToImage()), + wxPoint(bitmapFront.GetWidth(), (transparentImage.GetHeight() - bitmapText.GetHeight()) / 2), + transparentImage); + + if (bitmapBack.IsOk()) + writeToImage(wxImage(bitmapBack.ConvertToImage()), + wxPoint(bitmapFront.GetWidth() + bitmapText.GetWidth(), (transparentImage.GetHeight() - bitmapBack.GetHeight()) / 2), + transparentImage); + + //adjust button size + wxSize minSize = GetMinSize(); + + //SetMinSize() instead of SetSize() is needed here for wxWindows layout determination to work corretly + wxBitmapButton::SetMinSize(wxSize(std::max(width + 10, minSize.GetWidth()), std::max(height + 5, minSize.GetHeight()))); + + //finally set bitmap + wxBitmapButton::SetBitmapLabel(wxBitmap(transparentImage)); +} diff --git a/library/customButton.h b/library/customButton.h new file mode 100644 index 00000000..1f3f50ec --- /dev/null +++ b/library/customButton.h @@ -0,0 +1,40 @@ +/*************************************************************** + * Purpose: wxButton with bitmap label + * Author: ZenJu (zhnmju123@gmx.de) + * Created: Feb. 2009 + **************************************************************/ + +#ifndef CUSTOMBUTTON_H_INCLUDED +#define CUSTOMBUTTON_H_INCLUDED + +#include <wx/bmpbuttn.h> + + +//wxButtonWithImage behaves like wxButton but optionally adds bitmap labels +class wxButtonWithImage : public wxBitmapButton +{ +public: + wxButtonWithImage(wxWindow *parent, + wxWindowID id, + const wxString& label, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxValidator& validator = wxDefaultValidator, + const wxString& name = wxButtonNameStr); + + void setBitmapFront(const wxBitmap& bitmap); + void setTextLabel( const wxString& text); + void setBitmapBack( const wxBitmap& bitmap); + +private: + wxBitmap createBitmapFromText(const wxString& text); + void refreshButtonLabel(); + + wxBitmap bitmapFront; + wxString textLabel; + wxBitmap bitmapBack; +}; + + +#endif // CUSTOMBUTTON_H_INCLUDED diff --git a/library/fileHandling.cpp b/library/fileHandling.cpp index eb14b2f6..688d3640 100644 --- a/library/fileHandling.cpp +++ b/library/fileHandling.cpp @@ -8,9 +8,9 @@ #endif // FFS_WIN inline -bool endsWithPathSeparator(const wxChar* name) +bool endsWithPathSeparator(const Zstring& name) { - size_t len = wxStrlen(name); + const size_t len = name.length(); return len && (name[len - 1] == GlobalResources::FILE_NAME_SEPARATOR); } @@ -84,12 +84,12 @@ bool moveToRecycleBin(const Zstring& filename) throw(RuntimeException) inline void FreeFileSync::removeFile(const Zstring& filename, const bool useRecycleBin) { - if (!wxFileExists(filename)) return; //this is NOT an error situation: the manual deletion relies on it! + if (!wxFileExists(filename.c_str())) return; //this is NOT an error situation: the manual deletion relies on it! if (useRecycleBin) { if (!moveToRecycleBin(filename)) - throw FileError(wxString(_("Error moving to recycle bin:")) + wxT(" \"") + filename.c_str() + wxT("\"")); + throw FileError(Zstring(_("Error moving to recycle bin:")) + wxT(" \"") + filename + wxT("\"")); return; } @@ -97,11 +97,11 @@ void FreeFileSync::removeFile(const Zstring& filename, const bool useRecycleBin) if (!SetFileAttributes( filename.c_str(), //address of filename FILE_ATTRIBUTE_NORMAL //attributes to set - )) throw FileError(wxString(_("Error deleting file:")) + wxT(" \"") + filename.c_str() + wxT("\"")); + )) throw FileError(Zstring(_("Error deleting file:")) + wxT(" \"") + filename + wxT("\"")); #endif //FFS_WIN - if (!wxRemoveFile(filename)) - throw FileError(wxString(_("Error deleting file:")) + wxT(" \"") + filename.c_str() + wxT("\"")); + if (!wxRemoveFile(filename.c_str())) + throw FileError(Zstring(_("Error deleting file:")) + wxT(" \"") + filename + wxT("\"")); } @@ -112,12 +112,12 @@ void FreeFileSync::removeDirectory(const Zstring& directory, const bool useRecyc if (useRecycleBin) { if (!moveToRecycleBin(directory)) - throw FileError(wxString(_("Error moving to recycle bin:")) + wxT(" \"") + directory.c_str() + wxT("\"")); + throw FileError(Zstring(_("Error moving to recycle bin:")) + wxT(" \"") + directory + wxT("\"")); return; } - vector<Zstring> fileList; - vector<Zstring> dirList; + std::vector<Zstring> fileList; + std::vector<Zstring> dirList; try { //should be executed in own scope so that directory access does not disturb deletion! @@ -125,7 +125,7 @@ void FreeFileSync::removeDirectory(const Zstring& directory, const bool useRecyc } catch (const FileError& e) { - throw FileError(wxString(_("Error deleting directory:")) + wxT(" \"") + directory.c_str() + wxT("\"")); + throw FileError(Zstring(_("Error deleting directory:")) + wxT(" \"") + directory + wxT("\"")); } for (unsigned int j = 0; j < fileList.size(); ++j) @@ -139,11 +139,11 @@ void FreeFileSync::removeDirectory(const Zstring& directory, const bool useRecyc if (!SetFileAttributes( dirList[j].c_str(), // address of directory name FILE_ATTRIBUTE_NORMAL)) // attributes to set - throw FileError(wxString(_("Error deleting directory:")) + wxT(" \"") + dirList[j].c_str() + wxT("\"")); + throw FileError(Zstring(_("Error deleting directory:")) + wxT(" \"") + dirList[j] + wxT("\"")); #endif // FFS_WIN - if (!wxRmdir(dirList[j])) - throw FileError(wxString(_("Error deleting directory:")) + wxT(" \"") + dirList[j].c_str() + wxT("\"")); + if (!wxRmdir(dirList[j].c_str())) + throw FileError(Zstring(_("Error deleting directory:")) + wxT(" \"") + dirList[j] + wxT("\"")); } } @@ -157,12 +157,12 @@ void FreeFileSync::createDirectory(const Zstring& directory, const int level) return; //try to create directory - if (wxMkdir(directory)) + if (wxMkdir(directory.c_str())) return; //if not successfull try to create parent folders first Zstring parentDir; - if (endsWithPathSeparator(directory.c_str())) //may be valid on first level of recursion at most! Usually never true! + if (endsWithPathSeparator(directory)) //may be valid on first level of recursion at most! Usually never true! { parentDir = directory.BeforeLast(GlobalResources::FILE_NAME_SEPARATOR); parentDir = parentDir.BeforeLast(GlobalResources::FILE_NAME_SEPARATOR); @@ -176,10 +176,10 @@ void FreeFileSync::createDirectory(const Zstring& directory, const int level) createDirectory(parentDir, level + 1); //now creation should be possible - if (!wxMkdir(directory)) + if (!wxMkdir(directory.c_str())) { if (level == 0) - throw FileError(wxString(_("Error creating directory:")) + wxT(" \"") + directory.c_str() + wxT("\"")); + throw FileError(Zstring(_("Error creating directory:")) + wxT(" \"") + directory + wxT("\"")); } } @@ -189,12 +189,12 @@ 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(wxString(_("Error reading file attributes:")) + wxT(" \"") + source.c_str() + wxT("\"")); + throw FileError(Zstring(_("Error reading folder attributes:")) + wxT(" \"") + source + wxT("\"")); if (!SetFileAttributes( target.c_str(), // address of filename attr)) // address of attributes to set - throw FileError(wxString(_("Error writing file attributes:")) + wxT(" \"") + target.c_str() + wxT("\"")); + throw FileError(Zstring(_("Error writing folder attributes:")) + wxT(" \"") + target + wxT("\"")); #elif defined FFS_LINUX //Linux doesn't use attributes for files or folders #endif @@ -204,19 +204,19 @@ void FreeFileSync::copyFolderAttributes(const Zstring& source, const Zstring& ta class GetAllFilesSimple : public wxDirTraverser { public: - GetAllFilesSimple(vector<Zstring>& files, vector<Zstring>& subDirectories) : + GetAllFilesSimple(std::vector<Zstring>& files, std::vector<Zstring>& subDirectories) : m_files(files), m_dirs(subDirectories) {} wxDirTraverseResult OnDir(const wxString& dirname) { - m_dirs.push_back(dirname); + m_dirs.push_back(dirname.c_str()); return wxDIR_CONTINUE; } wxDirTraverseResult OnFile(const wxString& filename) { - m_files.push_back(filename); + m_files.push_back(filename.c_str()); return wxDIR_CONTINUE; } @@ -227,22 +227,22 @@ public: } private: - vector<Zstring>& m_files; - vector<Zstring>& m_dirs; + std::vector<Zstring>& m_files; + std::vector<Zstring>& m_dirs; }; -void FreeFileSync::getAllFilesAndDirs(const Zstring& sourceDir, vector<Zstring>& files, vector<Zstring>& directories) throw(FileError) +void FreeFileSync::getAllFilesAndDirs(const Zstring& sourceDir, std::vector<Zstring>& files, std::vector<Zstring>& directories) throw(FileError) { files.clear(); directories.clear(); //get all files and directories from current directory (and subdirectories) - wxDir dir(sourceDir); + wxDir dir(sourceDir.c_str()); GetAllFilesSimple traverser(files, directories); if (dir.Traverse(traverser) == (size_t)-1) - throw FileError(wxString(_("Error traversing directory:")) + wxT(" \"") + sourceDir.c_str() + wxT("\"")); + throw FileError(Zstring(_("Error traversing directory:")) + wxT(" \"") + sourceDir + wxT("\"")); } @@ -267,10 +267,10 @@ void getWin32FileInformation(const WIN32_FIND_DATA& input, FreeFileSync::FileInf { //convert UTC FILETIME to ANSI C format (number of seconds since Jan. 1st 1970 UTC) wxULongLong writeTimeLong(input.ftLastWriteTime.dwHighDateTime, input.ftLastWriteTime.dwLowDateTime); - writeTimeLong /= 10000000; //reduce precision to 1 second (FILETIME has unit 10^-7 s) - writeTimeLong -= wxULongLong(2, 3054539008UL); //timeshift between ansi C time and FILETIME in seconds == 11644473600s - output.lastWriteTimeRaw = writeTimeLong.GetLo(); //it should fit into a 32bit variable now - assert(writeTimeLong.GetHi() == 0); + writeTimeLong /= 10000000; //reduce precision to 1 second (FILETIME has unit 10^-7 s) + writeTimeLong -= wxULongLong(2, 3054539008UL); //timeshift between ansi C time and FILETIME in seconds == 11644473600s + assert(writeTimeLong.GetHi() == 0); //it should fit into a 32bit variable now + output.lastWriteTimeRaw = writeTimeLong.GetLo(); output.fileSize = wxULongLong(input.nFileSizeHigh, input.nFileSizeLow); } @@ -281,7 +281,7 @@ class EnhancedFileTraverser : public wxDirTraverser public: EnhancedFileTraverser(FreeFileSync::FullDetailFileTraverser* sink) : m_sink(sink) {} - virtual wxDirTraverseResult OnFile(const wxString& filename) + wxDirTraverseResult OnFile(const wxString& filename) //virtual impl. { struct stat fileInfo; if (stat(filename.c_str(), &fileInfo) != 0) @@ -291,17 +291,17 @@ public: details.lastWriteTimeRaw = fileInfo.st_mtime; //UTC time(ANSI C format); unit: 1 second details.fileSize = fileInfo.st_size; - return m_sink->OnFile(filename, details); + return m_sink->OnFile(filename.c_str(), details); } - virtual wxDirTraverseResult OnDir(const wxString& dirname) + wxDirTraverseResult OnDir(const wxString& dirname) //virtual impl. { - return m_sink->OnDir(dirname); + return m_sink->OnDir(dirname.c_str()); } - virtual wxDirTraverseResult OnOpenError(const wxString& errorText) + wxDirTraverseResult OnOpenError(const wxString& errorText) //virtual impl. { - return m_sink->OnError(errorText); + return m_sink->OnError(errorText.c_str()); } private: @@ -322,7 +322,7 @@ bool FreeFileSync::traverseInDetail(const Zstring& directory, FullDetailFileTrav } Zstring directoryFormatted = directory; - if (!endsWithPathSeparator(directoryFormatted.c_str())) + if (!endsWithPathSeparator(directoryFormatted)) directoryFormatted += GlobalResources::FILE_NAME_SEPARATOR; const Zstring filespec = directoryFormatted + wxT("*.*"); @@ -403,10 +403,10 @@ bool FreeFileSync::traverseInDetail(const Zstring& directory, FullDetailFileTrav #elif defined FFS_LINUX //use standard file traverser and enrich output with additional file information - //could be improved with own traversing algorithm for optimized performance + //could be improved with custom traversing algorithm for optimized performance EnhancedFileTraverser traverser(sink); - wxDir dir(directory); + wxDir dir(directory.c_str()); if (dir.IsOpened()) dir.Traverse(traverser); diff --git a/library/fileHandling.h b/library/fileHandling.h index cd86333b..5578ce91 100644 --- a/library/fileHandling.h +++ b/library/fileHandling.h @@ -8,21 +8,21 @@ class FileError //Exception class used to notify file/directory copy/delete errors { public: - FileError(const wxString& txt) : errorMessage(txt) {} + FileError(const Zstring& txt) : errorMessage(txt) {} - wxString show() const + Zstring show() const { return errorMessage; } private: - wxString errorMessage; + Zstring errorMessage; }; namespace FreeFileSync { - void getAllFilesAndDirs(const Zstring& sourceDir, vector<Zstring>& files, vector<Zstring>& directories) throw(FileError); + 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 diff --git a/library/globalFunctions.cpp b/library/globalFunctions.cpp index 7f8b57c0..eed6dfe9 100644 --- a/library/globalFunctions.cpp +++ b/library/globalFunctions.cpp @@ -11,27 +11,27 @@ int globalFunctions::round(const double d) } -string globalFunctions::numberToString(const unsigned int number) +std::string globalFunctions::numberToString(const unsigned int number) { char result[100]; sprintf(result, "%u", number); - return string(result); + return std::string(result); } -string globalFunctions::numberToString(const int number) +std::string globalFunctions::numberToString(const int number) { char result[100]; sprintf(result, "%d", number); - return string(result); + return std::string(result); } -string globalFunctions::numberToString(const float number) +std::string globalFunctions::numberToString(const float number) { char result[100]; sprintf(result, "%f", number); - return string(result); + return std::string(result); } @@ -53,14 +53,14 @@ wxString globalFunctions::numberToWxString(const float number) } -int globalFunctions::stringToInt(const string& number) +int globalFunctions::stringToInt(const std::string& number) { return atoi(number.c_str()); } inline -double globalFunctions::stringToDouble(const string& number) +double globalFunctions::stringToDouble(const std::string& number) { return atof(number.c_str()); } @@ -96,7 +96,7 @@ wxString& globalFunctions::includeNumberSeparator(wxString& number) } -int globalFunctions::readInt(ifstream& stream) +int globalFunctions::readInt(std::ifstream& stream) { int result = 0; char* buffer = reinterpret_cast<char*>(&result); @@ -105,7 +105,7 @@ int globalFunctions::readInt(ifstream& stream) } -void globalFunctions::writeInt(ofstream& stream, const int number) +void globalFunctions::writeInt(std::ofstream& stream, const int number) { const char* buffer = reinterpret_cast<const char*>(&number); stream.write(buffer, sizeof(int)); diff --git a/library/globalFunctions.h b/library/globalFunctions.h index f46a5906..b4ccba5c 100644 --- a/library/globalFunctions.h +++ b/library/globalFunctions.h @@ -10,8 +10,6 @@ #include <wx/stream.h> #include <wx/stopwatch.h> -using namespace std; - namespace globalFunctions { @@ -23,24 +21,24 @@ namespace globalFunctions return(d<0?-d:d); } - string numberToString(const unsigned int number); //convert number to string - string numberToString(const int number); //convert number to string - string numberToString(const float number); //convert number to string + std::string numberToString(const unsigned int number); //convert number to string + std::string numberToString(const int number); //convert number to string + std::string numberToString(const float number); //convert number to string wxString numberToWxString(const unsigned int number); //convert number to wxString wxString numberToWxString(const int number); //convert number to wxString wxString numberToWxString(const float number); //convert number to wxString - int stringToInt( const string& number); //convert String to number - double stringToDouble(const string& number); //convert String to number + int stringToInt( const std::string& number); //convert String to number + double stringToDouble(const std::string& number); //convert String to number int wxStringToInt( const wxString& number); //convert wxString to number double wxStringToDouble(const wxString& number); //convert wxString to number wxString& includeNumberSeparator(wxString& number); - int readInt(ifstream& stream); //read int from file stream - void writeInt(ofstream& stream, const int number); //write int to filestream + int readInt(std::ifstream& stream); //read int from file stream + void writeInt(std::ofstream& stream, const int number); //write int to filestream int readInt(wxInputStream& stream); //read int from file stream void writeInt(wxOutputStream& stream, const int number); //write int to filestream @@ -108,12 +106,12 @@ private: //Note: the following lines are a performance optimization for deleting elements from a vector. It is incredibly faster to create a new //vector and leave specific elements out than to delete row by row and force recopying of most elements for each single deletion (linear vs quadratic runtime) template <class T> -void removeRowsFromVector(vector<T>& grid, const set<int>& rowsToRemove) +void removeRowsFromVector(std::vector<T>& grid, const std::set<int>& rowsToRemove) { - vector<T> temp; + std::vector<T> temp; int rowToSkip = -1; //keep it an INT! - set<int>::iterator rowToSkipIndex = rowsToRemove.begin(); + std::set<int>::iterator rowToSkipIndex = rowsToRemove.begin(); if (rowToSkipIndex != rowsToRemove.end()) rowToSkip = *rowToSkipIndex; diff --git a/library/misc.cpp b/library/misc.cpp index 050be108..f5c562c7 100644 --- a/library/misc.cpp +++ b/library/misc.cpp @@ -19,8 +19,7 @@ void exchangeEscapeChars(wxString& data) { //read next character ++input; - value = *input; - if (value == wxChar(0)) + if ((value = *input) == wxChar(0)) break; switch (value) @@ -60,23 +59,32 @@ void CustomLocale::setLanguage(const int language) { currentLanguage = language; - string languageFile; + std::string languageFile; switch (language) { - case wxLANGUAGE_GERMAN: - languageFile = "german.lng"; + case wxLANGUAGE_CHINESE_SIMPLIFIED: + languageFile = "Languages/chinese_simple.lng"; + break; + case wxLANGUAGE_DUTCH: + languageFile = "Languages/dutch.lng"; break; case wxLANGUAGE_FRENCH: - languageFile = "french.lng"; + languageFile = "Languages/french.lng"; + break; + case wxLANGUAGE_GERMAN: + languageFile = "Languages/german.lng"; + break; + case wxLANGUAGE_ITALIAN: + languageFile = "Languages/italian.lng"; break; case wxLANGUAGE_JAPANESE: - languageFile = "japanese.lng"; + languageFile = "Languages/japanese.lng"; break; - case wxLANGUAGE_DUTCH: - languageFile = "dutch.lng"; + case wxLANGUAGE_POLISH: + languageFile = "Languages/polish.lng"; break; - case wxLANGUAGE_CHINESE_SIMPLIFIED: - languageFile = "chinese_simple.lng"; + case wxLANGUAGE_PORTUGUESE: + languageFile = "Languages/portuguese.lng"; break; default: languageFile.clear(); @@ -96,7 +104,7 @@ void CustomLocale::setLanguage(const int language) char temp[bufferSize]; if (!languageFile.empty()) { - ifstream langFile(languageFile.c_str(), ios::binary); + std::ifstream langFile(languageFile.c_str(), std::ios::binary); if (langFile) { TranslationLine currentLine; diff --git a/library/misc.h b/library/misc.h index 5fa2c943..c3e960ff 100644 --- a/library/misc.h +++ b/library/misc.h @@ -6,7 +6,6 @@ #include <wx/intl.h> #include <wx/panel.h> -using namespace std; struct TranslationLine { @@ -26,7 +25,7 @@ struct TranslationLine return (original == b.original); } }; -typedef set<TranslationLine> Translation; +typedef std::set<TranslationLine> Translation; class CustomLocale : public wxLocale @@ -44,7 +43,7 @@ public: const wxChar* GetString(const wxChar* szOrigString, const wxChar* szDomain = NULL) const; - static const string FfsLanguageDat; + static const std::string FfsLanguageDat; private: Translation translationDB; diff --git a/library/multithreading.cpp b/library/multithreading.cpp index bf5918d2..f7f5ed04 100644 --- a/library/multithreading.cpp +++ b/library/multithreading.cpp @@ -39,6 +39,7 @@ class WorkerThread : public wxThread public: WorkerThread(UpdateWhileExecuting* handler) : + wxThread(wxTHREAD_DETACHED), readyToBeginProcessing(), beginProcessing(readyToBeginProcessing), threadIsInitialized(false), diff --git a/library/processXml.cpp b/library/processXml.cpp index 04048124..80ac190b 100644 --- a/library/processXml.cpp +++ b/library/processXml.cpp @@ -8,16 +8,16 @@ using namespace globalFunctions; using namespace xmlAccess; //small helper functions -bool readXmlElementValue(string& output, const TiXmlElement* parent, const string& name); -bool readXmlElementValue(int& output, const TiXmlElement* parent, const string& name); -bool readXmlElementValue(CompareVariant& output, const TiXmlElement* parent, const string& name); -bool readXmlElementValue(SyncConfiguration::Direction& output, const TiXmlElement* parent, const string& name); -bool readXmlElementValue(bool& output, const TiXmlElement* parent, const string& name); +bool readXmlElementValue(std::string& output, const TiXmlElement* parent, const std::string& name); +bool readXmlElementValue(int& output, const TiXmlElement* parent, const std::string& name); +bool readXmlElementValue(CompareVariant& output, const TiXmlElement* parent, const std::string& name); +bool readXmlElementValue(SyncConfiguration::Direction& output, const TiXmlElement* parent, const std::string& name); +bool readXmlElementValue(bool& output, const TiXmlElement* parent, const std::string& name); -void addXmlElement(TiXmlElement* parent, const string& name, const string& value); -void addXmlElement(TiXmlElement* parent, const string& name, const int value); -void addXmlElement(TiXmlElement* parent, const string& name, const SyncConfiguration::Direction value); -void addXmlElement(TiXmlElement* parent, const string& name, const bool value); +void addXmlElement(TiXmlElement* parent, const std::string& name, const std::string& value); +void addXmlElement(TiXmlElement* parent, const std::string& name, const int value); +void addXmlElement(TiXmlElement* parent, const std::string& name, const SyncConfiguration::Direction value); +void addXmlElement(TiXmlElement* parent, const std::string& name, const bool value); class XmlConfigInput @@ -40,7 +40,7 @@ public: private: //read basic FreefileSync settings (used by commandline and GUI), return true if ALL values have been retrieved successfully - bool readXmlMainConfig(MainConfiguration& mainCfg, vector<FolderPair>& directoryPairs); + bool readXmlMainConfig(MainConfiguration& mainCfg, std::vector<FolderPair>& directoryPairs); TiXmlDocument doc; bool loadSuccess; @@ -56,15 +56,15 @@ public: bool writeToFile(); //write gui settings - bool writeXmlGuiConfig(const XmlGuiConfig& inputCfg); + bool writeXmlGuiConfig(const XmlGuiConfig& outputCfg); //write batch settings - bool writeXmlBatchConfig(const XmlBatchConfig& inputCfg); + bool writeXmlBatchConfig(const XmlBatchConfig& outputCfg); //write global settings - bool writeXmlGlobalSettings(const XmlGlobalSettings& inputCfg); + bool writeXmlGlobalSettings(const XmlGlobalSettings& outputCfg); private: //write basic FreefileSync settings (used by commandline and GUI), return true if everything was written successfully - bool writeXmlMainConfig(const MainConfiguration& mainCfg, const vector<FolderPair>& directoryPairs); + bool writeXmlMainConfig(const MainConfiguration& mainCfg, const std::vector<FolderPair>& directoryPairs); TiXmlDocument doc; const wxString& m_fileName; @@ -89,18 +89,18 @@ XmlType xmlAccess::getXmlType(const wxString& filename) TiXmlElement* root = doc.RootElement(); - if (!root || (root->ValueStr() != string("FreeFileSync"))) //check for FFS configuration xml + if (!root || (root->ValueStr() != std::string("FreeFileSync"))) //check for FFS configuration xml return XML_OTHER; const char* cfgType = root->Attribute("XmlType"); if (!cfgType) return XML_OTHER; - if (string(cfgType) == "BATCH") + if (std::string(cfgType) == "BATCH") return XML_BATCH_CONFIG; - else if (string(cfgType) == "GUI") + else if (std::string(cfgType) == "GUI") return XML_GUI_CONFIG; - else if (string(cfgType) == "GLOBAL") + else if (std::string(cfgType) == "GLOBAL") return XML_GLOBAL_SETTINGS; else return XML_OTHER; @@ -115,10 +115,10 @@ XmlGuiConfig xmlAccess::readGuiConfig(const wxString& filename) XmlGuiConfig outputCfg; if (!inputFile.loadedSuccessfully()) - throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + filename + wxT("\"")); + throw FileError(Zstring(_("Error reading file:")) + wxT(" \"") + filename.c_str() + wxT("\"")); if (!inputFile.readXmlGuiConfig(outputCfg)) //read GUI layout configuration - throw FileError(wxString(_("Error parsing configuration file:")) + wxT(" \"") + filename + wxT("\"")); + throw FileError(Zstring(_("Error parsing configuration file:")) + wxT(" \"") + filename.c_str() + wxT("\"")); return outputCfg; } @@ -132,10 +132,10 @@ XmlBatchConfig xmlAccess::readBatchConfig(const wxString& filename) XmlBatchConfig outputCfg; if (!inputFile.loadedSuccessfully()) - throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + filename + wxT("\"")); + throw FileError(Zstring(_("Error reading file:")) + wxT(" \"") + filename.c_str() + wxT("\"")); if (!inputFile.readXmlBatchConfig(outputCfg)) - throw FileError(wxString(_("Error parsing configuration file:")) + wxT(" \"") + filename + wxT("\"")); + throw FileError(Zstring(_("Error parsing configuration file:")) + wxT(" \"") + filename.c_str() + wxT("\"")); return outputCfg; } @@ -149,47 +149,47 @@ XmlGlobalSettings xmlAccess::readGlobalSettings() XmlGlobalSettings outputCfg; if (!inputFile.loadedSuccessfully()) - throw FileError(wxString(_("Error reading file:")) + wxT(" \"") + FreeFileSync::GLOBAL_CONFIG_FILE + wxT("\"")); + throw FileError(Zstring(_("Error reading file:")) + wxT(" \"") + FreeFileSync::GLOBAL_CONFIG_FILE.c_str() + wxT("\"")); if (!inputFile.readXmlGlobalSettings(outputCfg)) - throw FileError(wxString(_("Error parsing configuration file:")) + wxT(" \"") + FreeFileSync::GLOBAL_CONFIG_FILE + wxT("\"")); + throw FileError(Zstring(_("Error parsing configuration file:")) + wxT(" \"") + FreeFileSync::GLOBAL_CONFIG_FILE.c_str() + wxT("\"")); return outputCfg; } -void xmlAccess::writeGuiConfig(const wxString& filename, const XmlGuiConfig& inputCfg) +void xmlAccess::writeGuiConfig(const wxString& filename, const XmlGuiConfig& outputCfg) { XmlConfigOutput outputFile(filename, XML_GUI_CONFIG); //populate and write XML tree - if ( !outputFile.writeXmlGuiConfig(inputCfg) || //add GUI layout configuration settings + if ( !outputFile.writeXmlGuiConfig(outputCfg) || //add GUI layout configuration settings !outputFile.writeToFile()) //save XML - throw FileError(wxString(_("Error writing file:")) + wxT(" \"") + filename + wxT("\"")); + throw FileError(Zstring(_("Error writing file:")) + wxT(" \"") + filename.c_str() + wxT("\"")); return; } -void xmlAccess::writeBatchConfig(const wxString& filename, const XmlBatchConfig& inputCfg) +void xmlAccess::writeBatchConfig(const wxString& filename, const XmlBatchConfig& outputCfg) { XmlConfigOutput outputFile(filename, XML_BATCH_CONFIG); //populate and write XML tree - if ( !outputFile.writeXmlBatchConfig(inputCfg) || //add GUI layout configuration settings + if ( !outputFile.writeXmlBatchConfig(outputCfg) || //add GUI layout configuration settings !outputFile.writeToFile()) //save XML - throw FileError(wxString(_("Error writing file:")) + wxT(" \"") + filename + wxT("\"")); + throw FileError(Zstring(_("Error writing file:")) + wxT(" \"") + filename.c_str() + wxT("\"")); return; } -void xmlAccess::writeGlobalSettings(const XmlGlobalSettings& inputCfg) +void xmlAccess::writeGlobalSettings(const XmlGlobalSettings& outputCfg) { XmlConfigOutput outputFile(FreeFileSync::GLOBAL_CONFIG_FILE, XML_GLOBAL_SETTINGS); //populate and write XML tree - if ( !outputFile.writeXmlGlobalSettings(inputCfg) || //add GUI layout configuration settings + if ( !outputFile.writeXmlGlobalSettings(outputCfg) || //add GUI layout configuration settings !outputFile.writeToFile()) //save XML - throw FileError(wxString(_("Error writing file:")) + wxT(" \"") + FreeFileSync::GLOBAL_CONFIG_FILE + wxT("\"")); + throw FileError(Zstring(_("Error writing file:")) + wxT(" \"") + FreeFileSync::GLOBAL_CONFIG_FILE.c_str() + wxT("\"")); return; } @@ -212,17 +212,17 @@ XmlConfigInput::XmlConfigInput(const wxString& fileName, const XmlType type) : { TiXmlElement* root = doc.RootElement(); - if (root && (root->ValueStr() == string("FreeFileSync"))) //check for FFS configuration xml + if (root && (root->ValueStr() == std::string("FreeFileSync"))) //check for FFS configuration xml { const char* cfgType = root->Attribute("XmlType"); if (cfgType) { if (type == XML_GUI_CONFIG) - loadSuccess = string(cfgType) == "GUI"; + loadSuccess = std::string(cfgType) == "GUI"; else if (type == XML_BATCH_CONFIG) - loadSuccess = string(cfgType) == "BATCH"; + loadSuccess = std::string(cfgType) == "BATCH"; else if (type == XML_GLOBAL_SETTINGS) - loadSuccess = string(cfgType) == "GLOBAL"; + loadSuccess = std::string(cfgType) == "GLOBAL"; } } } @@ -230,7 +230,7 @@ XmlConfigInput::XmlConfigInput(const wxString& fileName, const XmlType type) : } -bool readXmlElementValue(string& output, const TiXmlElement* parent, const string& name) +bool readXmlElementValue(std::string& output, const TiXmlElement* parent, const std::string& name) { if (parent) { @@ -250,9 +250,9 @@ bool readXmlElementValue(string& output, const TiXmlElement* parent, const strin } -bool readXmlElementValue(int& output, const TiXmlElement* parent, const string& name) +bool readXmlElementValue(int& output, const TiXmlElement* parent, const std::string& name) { - string temp; + std::string temp; if (readXmlElementValue(temp, parent, name)) { output = stringToInt(temp); @@ -263,7 +263,7 @@ bool readXmlElementValue(int& output, const TiXmlElement* parent, const string& } -bool readXmlElementValue(CompareVariant& output, const TiXmlElement* parent, const string& name) +bool readXmlElementValue(CompareVariant& output, const TiXmlElement* parent, const std::string& name) { int dummy = 0; if (readXmlElementValue(dummy, parent, name)) @@ -276,9 +276,9 @@ bool readXmlElementValue(CompareVariant& output, const TiXmlElement* parent, con } -bool readXmlElementValue(SyncConfiguration::Direction& output, const TiXmlElement* parent, const string& name) +bool readXmlElementValue(SyncConfiguration::Direction& output, const TiXmlElement* parent, const std::string& name) { - string dummy; + std::string dummy; if (readXmlElementValue(dummy, parent, name)) { if (dummy == "left") @@ -295,9 +295,9 @@ bool readXmlElementValue(SyncConfiguration::Direction& output, const TiXmlElemen } -bool readXmlElementValue(bool& output, const TiXmlElement* parent, const string& name) +bool readXmlElementValue(bool& output, const TiXmlElement* parent, const std::string& name) { - string dummy; + std::string dummy; if (readXmlElementValue(dummy, parent, name)) { output = (dummy == "true"); @@ -308,7 +308,7 @@ bool readXmlElementValue(bool& output, const TiXmlElement* parent, const string& } -bool XmlConfigInput::readXmlMainConfig(MainConfiguration& mainCfg, vector<FolderPair>& directoryPairs) +bool XmlConfigInput::readXmlMainConfig(MainConfiguration& mainCfg, std::vector<FolderPair>& directoryPairs) { TiXmlElement* root = doc.RootElement(); if (!root) return false; @@ -323,7 +323,7 @@ bool XmlConfigInput::readXmlMainConfig(MainConfiguration& mainCfg, vector<Folder if (!cmpSettings || !syncConfig || !miscSettings || !filter) return false; - string tempString; + std::string tempString; //########################################################### //read compare variant if (!readXmlElementValue(mainCfg.compareVar, cmpSettings, "Variant")) return false; @@ -435,7 +435,7 @@ bool XmlConfigInput::readXmlGlobalSettings(XmlGlobalSettings& outputCfg) #ifdef FFS_WIN //daylight saving time check - readXmlElementValue(outputCfg.global.dstCheckActive, global, "DaylightSavingTimeCheckActive"); + readXmlElementValue(outputCfg.global.handleDstOnFat32, global, "HandleDaylightSavingTimeOnFAT"); #endif //folder dependency check @@ -453,50 +453,78 @@ bool XmlConfigInput::readXmlGlobalSettings(XmlGlobalSettings& outputCfg) readXmlElementValue(outputCfg.gui.isMaximized, mainWindow, "Maximized"); //########################################################### - //read column widths - TiXmlElement* leftColumn = TiXmlHandle(mainWindow).FirstChild("LeftColumns").FirstChild("Width").ToElement(); + //read column attributes + TiXmlElement* leftColumn = TiXmlHandle(mainWindow).FirstChild("LeftColumns").FirstChild("Column").ToElement(); + unsigned int colType = 0; while (leftColumn) { - const char* width = leftColumn->GetText(); - if (width) //may be NULL!! - outputCfg.gui.columnWidthLeft.push_back(stringToInt(width)); + const char* visible = leftColumn->Attribute("Visible"); + const char* position = leftColumn->Attribute("Position"); + const char* width = leftColumn->Attribute("Width"); + + if (visible && position && width) //may be NULL!! + { + XmlGlobalSettings::ColumnAttrib newAttrib; + newAttrib.type = XmlGlobalSettings::ColumnTypes(colType); + newAttrib.visible = std::string(visible) != std::string("false"); + newAttrib.position = stringToInt(position); + newAttrib.width = stringToInt(width); + outputCfg.gui.columnAttribLeft.push_back(newAttrib); + } else break; + leftColumn = leftColumn->NextSiblingElement(); + ++colType; } - TiXmlElement* rightColumn = TiXmlHandle(mainWindow).FirstChild("RightColumns").FirstChild("Width").ToElement(); + TiXmlElement* rightColumn = TiXmlHandle(mainWindow).FirstChild("RightColumns").FirstChild("Column").ToElement(); + colType = 0; while (rightColumn) { - const char* width = rightColumn->GetText(); - if (width) //may be NULL!! - outputCfg.gui.columnWidthRight.push_back(stringToInt(width)); + const char* visible = rightColumn->Attribute("Visible"); + const char* position = rightColumn->Attribute("Position"); + const char* width = rightColumn->Attribute("Width"); + + if (visible && position && width) //may be NULL!! + { + XmlGlobalSettings::ColumnAttrib newAttrib; + newAttrib.type = XmlGlobalSettings::ColumnTypes(colType); + newAttrib.visible = std::string(visible) != std::string("false"); + newAttrib.position = stringToInt(position); + newAttrib.width = stringToInt(width); + outputCfg.gui.columnAttribRight.push_back(newAttrib); + } else break; + rightColumn = rightColumn->NextSiblingElement(); + ++colType; } + } - //read column positions - TiXmlElement* leftColumnPos = TiXmlHandle(mainWindow).FirstChild("LeftColumnPositions").FirstChild("Position").ToElement(); - while (leftColumnPos) - { - const char* width = leftColumnPos->GetText(); - if (width) //may be NULL!! - outputCfg.gui.columnPositionsLeft.push_back(stringToInt(width)); - else - break; - leftColumnPos = leftColumnPos->NextSiblingElement(); - } + TiXmlElement* gui = hRoot.FirstChild("Gui").ToElement(); + if (gui) + { + //commandline for file manager integration + std::string tempString; + if (readXmlElementValue(tempString, gui, "FileManager")) + outputCfg.gui.commandLineFileManager = wxString::FromUTF8(tempString.c_str()); + } - TiXmlElement* rightColumnPos = TiXmlHandle(mainWindow).FirstChild("RightColumnPositions").FirstChild("Position").ToElement(); - while (rightColumnPos) + //load config file history + TiXmlElement* cfgHistory = hRoot.FirstChild("Gui").FirstChild("History").ToElement(); + if (cfgHistory) + { + TiXmlElement* cfgFile = TiXmlHandle(cfgHistory).FirstChild("File").ToElement(); + while (cfgFile) { - const char* width = rightColumnPos->GetText(); - if (width) //may be NULL!! - outputCfg.gui.columnPositionsRight.push_back(stringToInt(width)); + const char* fileName = cfgFile->GetText(); + if (fileName) //may be NULL!! + outputCfg.gui.cfgFileHistory.push_back(wxString::FromUTF8(fileName)); else break; - rightColumnPos = rightColumnPos->NextSiblingElement(); + cfgFile = cfgFile->NextSiblingElement(); } } @@ -546,7 +574,7 @@ bool XmlConfigOutput::writeToFile() } -void addXmlElement(TiXmlElement* parent, const string& name, const string& value) +void addXmlElement(TiXmlElement* parent, const std::string& name, const std::string& value) { if (parent) { @@ -557,35 +585,35 @@ void addXmlElement(TiXmlElement* parent, const string& name, const string& value } -void addXmlElement(TiXmlElement* parent, const string& name, const int value) +void addXmlElement(TiXmlElement* parent, const std::string& name, const int value) { addXmlElement(parent, name, numberToString(value)); } -void addXmlElement(TiXmlElement* parent, const string& name, const SyncConfiguration::Direction value) +void addXmlElement(TiXmlElement* parent, const std::string& name, const SyncConfiguration::Direction value) { if (value == SyncConfiguration::SYNC_DIR_LEFT) - addXmlElement(parent, name, string("left")); + addXmlElement(parent, name, std::string("left")); else if (value == SyncConfiguration::SYNC_DIR_RIGHT) - addXmlElement(parent, name, string("right")); + addXmlElement(parent, name, std::string("right")); else if (value == SyncConfiguration::SYNC_DIR_NONE) - addXmlElement(parent, name, string("none")); + addXmlElement(parent, name, std::string("none")); else assert(false); } -void addXmlElement(TiXmlElement* parent, const string& name, const bool value) +void addXmlElement(TiXmlElement* parent, const std::string& name, const bool value) { if (value) - addXmlElement(parent, name, string("true")); + addXmlElement(parent, name, std::string("true")); else - addXmlElement(parent, name, string("false")); + addXmlElement(parent, name, std::string("false")); } -bool XmlConfigOutput::writeXmlMainConfig(const MainConfiguration& mainCfg, const vector<FolderPair>& directoryPairs) +bool XmlConfigOutput::writeXmlMainConfig(const MainConfiguration& mainCfg, const std::vector<FolderPair>& directoryPairs) { TiXmlElement* root = doc.RootElement(); if (!root) return false; @@ -605,13 +633,13 @@ bool XmlConfigOutput::writeXmlMainConfig(const MainConfiguration& mainCfg, const cmpSettings->LinkEndChild(folders); //write folder pairs - for (vector<FolderPair>::const_iterator i = directoryPairs.begin(); i != directoryPairs.end(); ++i) + for (std::vector<FolderPair>::const_iterator i = directoryPairs.begin(); i != directoryPairs.end(); ++i) { TiXmlElement* folderPair = new TiXmlElement("Pair"); folders->LinkEndChild(folderPair); - addXmlElement(folderPair, "Left", string(wxString(i->leftDirectory.c_str()).ToUTF8())); - addXmlElement(folderPair, "Right", string(wxString(i->rightDirectory.c_str()).ToUTF8())); + addXmlElement(folderPair, "Left", std::string(wxString(i->leftDirectory.c_str()).ToUTF8())); + addXmlElement(folderPair, "Right", std::string(wxString(i->rightDirectory.c_str()).ToUTF8())); } //########################################################### @@ -637,8 +665,8 @@ bool XmlConfigOutput::writeXmlMainConfig(const MainConfiguration& mainCfg, const miscSettings->LinkEndChild(filter); addXmlElement(filter, "Active", mainCfg.filterIsActive); - addXmlElement(filter, "Include", string((mainCfg.includeFilter).ToUTF8())); - addXmlElement(filter, "Exclude", string((mainCfg.excludeFilter).ToUTF8())); + addXmlElement(filter, "Include", std::string((mainCfg.includeFilter).ToUTF8())); + addXmlElement(filter, "Exclude", std::string((mainCfg.excludeFilter).ToUTF8())); //other addXmlElement(miscSettings, "UseRecycler", mainCfg.useRecycleBin); @@ -649,10 +677,10 @@ bool XmlConfigOutput::writeXmlMainConfig(const MainConfiguration& mainCfg, const } -bool XmlConfigOutput::writeXmlGuiConfig(const XmlGuiConfig& inputCfg) +bool XmlConfigOutput::writeXmlGuiConfig(const XmlGuiConfig& outputCfg) { //write main config - if (!writeXmlMainConfig(inputCfg.mainCfg, inputCfg.directoryPairs)) + if (!writeXmlMainConfig(outputCfg.mainCfg, outputCfg.directoryPairs)) return false; //write GUI specific config @@ -668,16 +696,16 @@ bool XmlConfigOutput::writeXmlGuiConfig(const XmlGuiConfig& inputCfg) TiXmlElement* mainWindow = new TiXmlElement("Main"); windows->LinkEndChild(mainWindow); - addXmlElement(mainWindow, "HideFiltered", inputCfg.hideFilteredElements); + addXmlElement(mainWindow, "HideFiltered", outputCfg.hideFilteredElements); return true; } -bool XmlConfigOutput::writeXmlBatchConfig(const XmlBatchConfig& inputCfg) +bool XmlConfigOutput::writeXmlBatchConfig(const XmlBatchConfig& outputCfg) { //write main config - if (!writeXmlMainConfig(inputCfg.mainCfg, inputCfg.directoryPairs)) + if (!writeXmlMainConfig(outputCfg.mainCfg, outputCfg.directoryPairs)) return false; //write GUI specific config @@ -687,13 +715,13 @@ bool XmlConfigOutput::writeXmlBatchConfig(const XmlBatchConfig& inputCfg) TiXmlElement* batchConfig = new TiXmlElement("BatchConfig"); root->LinkEndChild(batchConfig); - addXmlElement(batchConfig, "Silent", inputCfg.silent); + addXmlElement(batchConfig, "Silent", outputCfg.silent); return true; } -bool XmlConfigOutput::writeXmlGlobalSettings(const XmlGlobalSettings& inputCfg) +bool XmlConfigOutput::writeXmlGlobalSettings(const XmlGlobalSettings& outputCfg) { TiXmlElement* root = doc.RootElement(); if (!root) return false; @@ -704,64 +732,83 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const XmlGlobalSettings& inputCfg) root->LinkEndChild(global); //program language - addXmlElement(global, "Language", inputCfg.global.programLanguage); + addXmlElement(global, "Language", outputCfg.global.programLanguage); #ifdef FFS_WIN //daylight saving time check - addXmlElement(global, "DaylightSavingTimeCheckActive", inputCfg.global.dstCheckActive); + addXmlElement(global, "HandleDaylightSavingTimeOnFAT", outputCfg.global.handleDstOnFat32); #endif //folder dependency check - addXmlElement(global, "FolderDependencyCheckActive", inputCfg.global.folderDependCheckActive); + addXmlElement(global, "FolderDependencyCheckActive", outputCfg.global.folderDependCheckActive); + //################################################################### - //write gui settings - TiXmlElement* guiLayout = new TiXmlElement("Gui"); - root->LinkEndChild(guiLayout); + //write global gui settings + TiXmlElement* gui = new TiXmlElement("Gui"); + root->LinkEndChild(gui); TiXmlElement* windows = new TiXmlElement("Windows"); - guiLayout->LinkEndChild(windows); + gui->LinkEndChild(windows); TiXmlElement* mainWindow = new TiXmlElement("Main"); windows->LinkEndChild(mainWindow); //window size - addXmlElement(mainWindow, "Width", inputCfg.gui.widthNotMaximized); - addXmlElement(mainWindow, "Height", inputCfg.gui.heightNotMaximized); + addXmlElement(mainWindow, "Width", outputCfg.gui.widthNotMaximized); + addXmlElement(mainWindow, "Height", outputCfg.gui.heightNotMaximized); //window position - addXmlElement(mainWindow, "PosX", inputCfg.gui.posXNotMaximized); - addXmlElement(mainWindow, "PosY", inputCfg.gui.posYNotMaximized); - addXmlElement(mainWindow, "Maximized", inputCfg.gui.isMaximized); + addXmlElement(mainWindow, "PosX", outputCfg.gui.posXNotMaximized); + addXmlElement(mainWindow, "PosY", outputCfg.gui.posYNotMaximized); + addXmlElement(mainWindow, "Maximized", outputCfg.gui.isMaximized); - //write column sizes + //write column attributes TiXmlElement* leftColumn = new TiXmlElement("LeftColumns"); mainWindow->LinkEndChild(leftColumn); - - for (unsigned int i = 0; i < inputCfg.gui.columnWidthLeft.size(); ++i) - addXmlElement(leftColumn, "Width", inputCfg.gui.columnWidthLeft[i]); + XmlGlobalSettings::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]; + if (colAttrib.visible) subElement->SetAttribute("Visible", "true"); + else subElement->SetAttribute("Visible", "false"); + subElement->SetAttribute("Position", colAttrib.position); + subElement->SetAttribute("Width", colAttrib.width); + } TiXmlElement* rightColumn = new TiXmlElement("RightColumns"); mainWindow->LinkEndChild(rightColumn); + XmlGlobalSettings::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]; + if (colAttrib.visible) subElement->SetAttribute("Visible", "true"); + else subElement->SetAttribute("Visible", "false"); + subElement->SetAttribute("Position", colAttrib.position); + subElement->SetAttribute("Width", colAttrib.width); + } - for (unsigned int i = 0; i < inputCfg.gui.columnWidthRight.size(); ++i) - addXmlElement(rightColumn, "Width", inputCfg.gui.columnWidthRight[i]); - - //write column positions - TiXmlElement* leftColumnPos = new TiXmlElement("LeftColumnPositions"); - mainWindow->LinkEndChild(leftColumnPos); + //commandline for file manager integration + addXmlElement(gui, "FileManager", std::string((outputCfg.gui.commandLineFileManager).ToUTF8())); - for (unsigned int i = 0; i < inputCfg.gui.columnPositionsLeft.size(); ++i) - addXmlElement(leftColumnPos, "Position", inputCfg.gui.columnPositionsLeft[i]); + //write config file history + TiXmlElement* cfgHistory = new TiXmlElement("History"); + gui->LinkEndChild(cfgHistory); - TiXmlElement* rightColumnPos = new TiXmlElement("RightColumnPositions"); - mainWindow->LinkEndChild(rightColumnPos); + for (unsigned int i = 0; i < outputCfg.gui.cfgFileHistory.size(); ++i) + addXmlElement(cfgHistory, "File", std::string(outputCfg.gui.cfgFileHistory[i].ToUTF8())); - for (unsigned int i = 0; i < inputCfg.gui.columnPositionsRight.size(); ++i) - addXmlElement(rightColumnPos, "Position", inputCfg.gui.columnPositionsRight[i]); //################################################################### - //write batch settings + //write global batch settings TiXmlElement* batch = new TiXmlElement("Batch"); root->LinkEndChild(batch); @@ -770,12 +817,13 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const XmlGlobalSettings& inputCfg) } -int xmlAccess::retrieveSystemLanguage() //map language dialects +int xmlAccess::retrieveSystemLanguage() { const int lang = wxLocale::GetSystemLanguage(); - switch (lang) + switch (lang) //map language dialects { + //variants of wxLANGUAGE_GERMAN case wxLANGUAGE_GERMAN_AUSTRIAN: case wxLANGUAGE_GERMAN_BELGIUM: case wxLANGUAGE_GERMAN_LIECHTENSTEIN: @@ -783,6 +831,7 @@ int xmlAccess::retrieveSystemLanguage() //map language dialects case wxLANGUAGE_GERMAN_SWISS: return wxLANGUAGE_GERMAN; + //variants of wxLANGUAGE_FRENCH case wxLANGUAGE_FRENCH_BELGIAN: case wxLANGUAGE_FRENCH_CANADIAN: case wxLANGUAGE_FRENCH_LUXEMBOURG: @@ -790,11 +839,15 @@ int xmlAccess::retrieveSystemLanguage() //map language dialects case wxLANGUAGE_FRENCH_SWISS: return wxLANGUAGE_FRENCH; - //case wxLANGUAGE_JAPANESE: - + //variants of wxLANGUAGE_DUTCH case wxLANGUAGE_DUTCH_BELGIAN: return wxLANGUAGE_DUTCH; + //variants of wxLANGUAGE_ITALIAN + case wxLANGUAGE_ITALIAN_SWISS: + return wxLANGUAGE_ITALIAN; + + //variants of wxLANGUAGE_CHINESE_SIMPLIFIED case wxLANGUAGE_CHINESE: case wxLANGUAGE_CHINESE_TRADITIONAL: case wxLANGUAGE_CHINESE_HONGKONG: @@ -803,7 +856,16 @@ int xmlAccess::retrieveSystemLanguage() //map language dialects case wxLANGUAGE_CHINESE_TAIWAN: return wxLANGUAGE_CHINESE_SIMPLIFIED; + //variants of wxLANGUAGE_PORTUGUESE + case wxLANGUAGE_PORTUGUESE_BRAZILIAN: + return wxLANGUAGE_PORTUGUESE; + + //case wxLANGUAGE_JAPANESE: + //case wxLANGUAGE_POLISH: + + default: + //all the rest: wxLANGUAGE_ENGLISH; return lang; } } diff --git a/library/processXml.h b/library/processXml.h index bc81556e..5f3f8ef9 100644 --- a/library/processXml.h +++ b/library/processXml.h @@ -25,7 +25,7 @@ namespace xmlAccess XmlGuiConfig() : hideFilteredElements(false) {} //initialize values MainConfiguration mainCfg; - vector<FolderPair> directoryPairs; + std::vector<FolderPair> directoryPairs; bool hideFilteredElements; }; @@ -36,31 +36,53 @@ namespace xmlAccess XmlBatchConfig() : silent(false) {} MainConfiguration mainCfg; - vector<FolderPair> directoryPairs; + std::vector<FolderPair> directoryPairs; bool silent; }; int retrieveSystemLanguage(); + 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 { _Global() : programLanguage(retrieveSystemLanguage()), #ifdef FFS_WIN - dstCheckActive(true), + handleDstOnFat32(true), #endif folderDependCheckActive(true) {} int programLanguage; #ifdef FFS_WIN - bool dstCheckActive; + bool handleDstOnFat32; #endif bool folderDependCheckActive; } global; +//--------------------------------------------------------------------- struct _Gui { _Gui() : @@ -68,30 +90,63 @@ namespace xmlAccess heightNotMaximized(wxDefaultCoord), posXNotMaximized(wxDefaultCoord), posYNotMaximized(wxDefaultCoord), - isMaximized(false) {} + isMaximized(false), +#ifdef FFS_WIN + commandLineFileManager(wxT("explorer /select, %x")) +#elif defined FFS_LINUX + commandLineFileManager(wxT("konqueror \"%path\"")) +#endif + {} int widthNotMaximized; int heightNotMaximized; int posXNotMaximized; int posYNotMaximized; bool isMaximized; - vector<int> columnWidthLeft; - vector<int> columnWidthRight; - vector<int> columnPositionsLeft; - vector<int> columnPositionsRight; + + ColumnAttributes columnAttribLeft; + ColumnAttributes columnAttribRight; + std::vector<wxString> cfgFileHistory; + wxString commandLineFileManager; } gui; +//--------------------------------------------------------------------- //struct _Batch }; + inline + bool sortByType(const XmlGlobalSettings::ColumnAttrib& a, const XmlGlobalSettings::ColumnAttrib& b) + { + return a.type < b.type; + } + + + inline + bool sortByPositionOnly(const XmlGlobalSettings::ColumnAttrib& a, const XmlGlobalSettings::ColumnAttrib& b) + { + return a.position < b.position; + } + + + inline + bool sortByPositionAndVisibility(const XmlGlobalSettings::ColumnAttrib& a, const XmlGlobalSettings::ColumnAttrib& b) + { + if (a.visible == false) //hidden elements shall appear at end of vector + return false; + if (b.visible == false) + return true; + return a.position < b.position; + } + + XmlGuiConfig readGuiConfig(const wxString& filename); XmlBatchConfig readBatchConfig(const wxString& filename); XmlGlobalSettings readGlobalSettings(); //used for both GUI and batch mode, independent from configuration instance - void writeGuiConfig(const wxString& filename, const XmlGuiConfig& inputCfg); - void writeBatchConfig(const wxString& filename, const XmlBatchConfig& inputCfg); - void writeGlobalSettings(const XmlGlobalSettings& inputCfg); + void writeGuiConfig(const wxString& filename, const XmlGuiConfig& outputCfg); + void writeBatchConfig(const wxString& filename, const XmlBatchConfig& outputCfg); + void writeGlobalSettings(const XmlGlobalSettings& outputCfg); } diff --git a/library/resources.cpp b/library/resources.cpp index 9169bf85..c60c259c 100644 --- a/library/resources.cpp +++ b/library/resources.cpp @@ -92,6 +92,12 @@ GlobalResources::GlobalResources() bitmapResource[wxT("filter.png")] = (bitmapFilter = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("batch.png")] = (bitmapBatch = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("batch_small.png")] = (bitmapBatchSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("move up.png")] = (bitmapMoveUp = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("move down.png")] = (bitmapMoveDown = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("checkbox true.png")] = (bitmapCheckBoxTrue = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("checkbox false.png")] = (bitmapCheckBoxFalse = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("settings.png")] = (bitmapSettings = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("settings_small.png")] = (bitmapSettingsSmall = new wxBitmap(wxNullBitmap)); //init all the other resource files animationMoney = new wxAnimation(wxNullAnimation); @@ -102,7 +108,7 @@ GlobalResources::GlobalResources() GlobalResources::~GlobalResources() { //free bitmap resources - for (map<wxString, wxBitmap*>::iterator i = bitmapResource.begin(); i != bitmapResource.end(); ++i) + for (std::map<wxString, wxBitmap*>::iterator i = bitmapResource.begin(); i != bitmapResource.end(); ++i) delete i->second; //free other resources @@ -117,7 +123,7 @@ void loadAnimFromZip(wxZipInputStream& zipInput, wxAnimation* animation) //Workaround for wxWidgets: //construct seekable input stream (zip-input stream is non-seekable) for wxAnimation::Load() //luckily this method call is very fast: below measurement precision! - vector<unsigned char> data; + std::vector<unsigned char> data; data.reserve(10000); int newValue = 0; @@ -141,7 +147,7 @@ void GlobalResources::load() wxZipInputStream resourceFile(input); wxZipEntry* entry = NULL; - map<wxString, wxBitmap*>::iterator bmp; + std::map<wxString, wxBitmap*>::iterator bmp; while ((entry = resourceFile.GetNextEntry())) { wxString name = entry->GetName(); diff --git a/library/resources.h b/library/resources.h index d08ce0ce..4eec185e 100644 --- a/library/resources.h +++ b/library/resources.h @@ -6,7 +6,6 @@ #include <wx/string.h> #include <map> -using namespace std; class GlobalResources { @@ -92,6 +91,12 @@ public: wxBitmap* bitmapFilter; wxBitmap* bitmapBatch; wxBitmap* bitmapBatchSmall; + wxBitmap* bitmapMoveUp; + wxBitmap* bitmapMoveDown; + wxBitmap* bitmapCheckBoxTrue; + wxBitmap* bitmapCheckBoxFalse; + wxBitmap* bitmapSettings; + wxBitmap* bitmapSettingsSmall; wxAnimation* animationMoney; wxAnimation* animationSync; @@ -100,7 +105,7 @@ public: private: //resource mapping - map<wxString, wxBitmap*> bitmapResource; + std::map<wxString, wxBitmap*> bitmapResource; }; diff --git a/library/sorting.h b/library/sorting.h index 560e246a..fabdad1f 100644 --- a/library/sorting.h +++ b/library/sorting.h @@ -5,6 +5,7 @@ #include "resources.h" #include "globalFunctions.h" +using namespace FreeFileSync; enum SideToSort { @@ -115,11 +116,11 @@ bool sortByFileName(const FileCompareLine& a, const FileCompareLine& b) 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 != string::npos) + if (pos != std::string::npos) stringA += pos + 1; pos = descrLineB->relativeName.Find(GlobalResources::FILE_NAME_SEPARATOR, true); //start search beginning from end - if (pos != string::npos) + if (pos != std::string::npos) stringB += pos + 1; return stringSmallerThan<sortAscending>(stringA, stringB); @@ -250,4 +251,20 @@ bool sortByDate(const FileCompareLine& a, const FileCompareLine& b) } +template <bool sortAscending> +inline +bool sortByCmpResult(const FileCompareLine& a, const FileCompareLine& b) +{ + //presort result: equal shall appear at end of list + if (a.cmpResult == FILE_EQUAL) + return false; + if (b.cmpResult == FILE_EQUAL) + return true; + + return sortAscending ? + a.cmpResult < b.cmpResult : + a.cmpResult > b.cmpResult; +} + + #endif // SORTING_H_INCLUDED diff --git a/library/statusHandler.h b/library/statusHandler.h index 4c12035d..bae1de8e 100644 --- a/library/statusHandler.h +++ b/library/statusHandler.h @@ -1,7 +1,7 @@ #ifndef STATUSHANDLER_H_INCLUDED #define STATUSHANDLER_H_INCLUDED -#include <wx/string.h> +#include "zstring.h" const int UI_UPDATE_INTERVAL = 100; //perform ui updates not more often than necessary, 100 seems to be a good value with only a minimal performance loss @@ -24,7 +24,7 @@ public: IGNORE_ERROR = 10, RETRY }; - virtual Response reportError(const wxString& text) = 0; + virtual Response reportError(const Zstring& text) = 0; }; @@ -45,10 +45,10 @@ public: }; //these methods have to be implemented in the derived classes to handle error and status information - virtual void updateStatusText(const wxString& text) = 0; + 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 wxString& text) = 0; + 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; diff --git a/library/zstring.cpp b/library/zstring.cpp index b84c9512..35704b01 100644 --- a/library/zstring.cpp +++ b/library/zstring.cpp @@ -44,14 +44,14 @@ int FreeFileSync::compareStringsWin32(const wchar_t* a, const wchar_t* b, const bCount); //size, in bytes or characters, of second string if (rv == 0) - throw RuntimeException(wxString(_("Error comparing strings!"))); + throw RuntimeException(wxString(wxT("Error comparing strings!"))); else return rv - 2; } #endif -size_t Zstring::Replace(const defaultChar* old, const defaultChar* replacement, bool replaceAll) +size_t Zstring::Replace(const DefaultChar* old, const DefaultChar* replacement, bool replaceAll) { const size_t oldLen = defaultLength(old); const size_t replacementLen = defaultLength(replacement); @@ -77,29 +77,29 @@ size_t Zstring::Replace(const defaultChar* old, const defaultChar* replacement, } -bool matchesHelper(const defaultChar* string, const defaultChar* mask) +bool matchesHelper(const DefaultChar* string, const DefaultChar* mask) { - for (defaultChar ch; (ch = *mask) != 0; ++mask) + for (DefaultChar ch; (ch = *mask) != 0; ++mask) { switch (ch) { - case defaultChar('?'): + case DefaultChar('?'): if (*string == 0) return false; else ++string; break; - case defaultChar('*'): + case DefaultChar('*'): //advance to next non-*/? char do { ++mask; ch = *mask; } - while (ch == defaultChar('*') || ch == defaultChar('?')); + while (ch == DefaultChar('*') || ch == DefaultChar('?')); //if match ends with '*': - if (ch == defaultChar(0)) + if (ch == DefaultChar(0)) return true; ++mask; @@ -123,7 +123,7 @@ bool matchesHelper(const defaultChar* string, const defaultChar* mask) } -bool Zstring::Matches(const defaultChar* mask) const +bool Zstring::Matches(const DefaultChar* mask) const { return matchesHelper(c_str(), mask); } @@ -137,7 +137,7 @@ Zstring& Zstring::Trim(bool fromRight) if (fromRight) { - const defaultChar* cursor = data + thisLen - 1; + const DefaultChar* cursor = data + thisLen - 1; while (cursor != data - 1 && defaultIsWhiteSpace(*cursor)) //break when pointing one char further than last skipped element --cursor; ++cursor; @@ -153,8 +153,8 @@ Zstring& Zstring::Trim(bool fromRight) } else { - defaultChar* cursor = data; - defaultChar ch; + DefaultChar* cursor = data; + DefaultChar ch; while ((ch = *cursor) != 0 && defaultIsWhiteSpace(ch)) ++cursor; @@ -185,7 +185,7 @@ Zstring& Zstring::MakeLower() if (descr->refCount > 1) //allocate new string { StringDescriptor* newDescr; - defaultChar* newData; + DefaultChar* newData; const size_t newCapacity = getCapacityToAllocate(thisLen); allocate(1, thisLen, newCapacity, newDescr, newData); @@ -224,7 +224,7 @@ Zstring Zstring::substr(size_t pos, size_t len) const } -size_t Zstring::rfind(const defaultChar ch, size_t pos) const +size_t Zstring::rfind(const DefaultChar ch, size_t pos) const { const size_t thisLen = length(); if (thisLen == 0) @@ -245,7 +245,7 @@ size_t Zstring::rfind(const defaultChar ch, size_t pos) const } -Zstring& Zstring::replace(size_t pos1, size_t n1, const defaultChar* str, size_t n2) +Zstring& Zstring::replace(size_t pos1, size_t n1, const DefaultChar* str, size_t n2) { assert(str < c_str() || c_str() + length() < str); //str mustn't point to data in this string assert(n1 <= length() - pos1); @@ -265,15 +265,15 @@ Zstring& Zstring::replace(size_t pos1, size_t n1, const defaultChar* str, size_t const size_t newCapacity = getCapacityToAllocate(newLen); StringDescriptor* newDescr; - defaultChar* newData; + DefaultChar* newData; allocate(1, newLen, newCapacity, newDescr, newData); //StringDescriptor* newDescr = new StringDescriptor(1, newLen, newCapacity); - //defaultChar* newData = new defaultChar[newCapacity + 1]; + //DefaultChar* newData = new DefaultChar[newCapacity + 1]; //assemble new string with replacement - memcpy(newData, data, pos1 * sizeof(defaultChar)); - memcpy(newData + pos1, str, n2 * sizeof(defaultChar)); - memcpy(newData + pos1 + n2, data + pos1 + n1, (oldLen - pos1 - n1) * sizeof(defaultChar)); + memcpy(newData, data, pos1 * sizeof(DefaultChar)); + memcpy(newData + pos1, str, n2 * sizeof(DefaultChar)); + memcpy(newData + pos1 + n2, data + pos1 + n1, (oldLen - pos1 - n1) * sizeof(DefaultChar)); newData[newLen] = 0; decRef(); @@ -282,10 +282,10 @@ Zstring& Zstring::replace(size_t pos1, size_t n1, const defaultChar* str, size_t } else { //overwrite current string - memcpy(data + pos1, str, n2 * sizeof(defaultChar)); + memcpy(data + pos1, str, n2 * sizeof(DefaultChar)); if (n1 > n2) { - memmove(data + pos1 + n2, data + pos1 + n1, (oldLen - pos1 - n1) * sizeof(defaultChar)); + memmove(data + pos1 + n2, data + pos1 + n1, (oldLen - pos1 - n1) * sizeof(DefaultChar)); data[newLen] = 0; descr->length = newLen; } @@ -295,7 +295,7 @@ Zstring& Zstring::replace(size_t pos1, size_t n1, const defaultChar* str, size_t } -Zstring& Zstring::operator=(const defaultChar* source) +Zstring& Zstring::operator=(const DefaultChar* source) { const size_t sourceLen = defaultLength(source); if (sourceLen == 0) @@ -305,7 +305,7 @@ Zstring& Zstring::operator=(const defaultChar* source) *this = Zstring(source, sourceLen); else { //overwrite this string - memcpy(data, source, sourceLen * sizeof(defaultChar)); + memcpy(data, source, sourceLen * sizeof(DefaultChar)); data[sourceLen] = 0; descr->length = sourceLen; } @@ -322,7 +322,7 @@ Zstring& Zstring::operator+=(const Zstring& other) const size_t newLen = thisLen + otherLen; copyBeforeWrite(newLen); - memcpy(data + thisLen, other.c_str(), otherLen * sizeof(defaultChar)); + memcpy(data + thisLen, other.c_str(), otherLen * sizeof(DefaultChar)); data[newLen] = 0; descr->length = newLen; } @@ -330,7 +330,7 @@ Zstring& Zstring::operator+=(const Zstring& other) } -Zstring& Zstring::operator+=(const defaultChar* other) +Zstring& Zstring::operator+=(const DefaultChar* other) { const size_t otherLen = defaultLength(other); if (otherLen != 0) @@ -339,7 +339,7 @@ Zstring& Zstring::operator+=(const defaultChar* other) const size_t newLen = thisLen + otherLen; copyBeforeWrite(newLen); - memcpy(data + thisLen, other, otherLen * sizeof(defaultChar)); + memcpy(data + thisLen, other, otherLen * sizeof(DefaultChar)); data[newLen] = 0; descr->length = newLen; } @@ -347,7 +347,7 @@ Zstring& Zstring::operator+=(const defaultChar* other) } -Zstring& Zstring::operator+=(defaultChar ch) +Zstring& Zstring::operator+=(DefaultChar ch) { const size_t oldLen = length(); copyBeforeWrite(oldLen + 1); @@ -368,15 +368,13 @@ void Zstring::copyBeforeWrite(const size_t capacityNeeded) const size_t newCapacity = getCapacityToAllocate(capacityNeeded); StringDescriptor* newDescr; - defaultChar* newData; + DefaultChar* newData; allocate(1, oldLength, newCapacity, newDescr, newData); - //StringDescriptor* newDescr = new StringDescriptor(1, oldLength, newCapacity); - //defaultChar* newData = new defaultChar[newCapacity + 1]; if (oldLength) { assert(oldLength <= newCapacity); - memcpy(newData, data, oldLength * sizeof(defaultChar)); + memcpy(newData, data, oldLength * sizeof(DefaultChar)); newData[oldLength] = 0; } decRef(); @@ -387,10 +385,10 @@ void Zstring::copyBeforeWrite(const size_t capacityNeeded) { //try to resize the current string (allocate anew if necessary) const size_t newCapacity = getCapacityToAllocate(capacityNeeded); - descr = (StringDescriptor*) realloc(descr, sizeof(StringDescriptor) + (newCapacity + 1) * sizeof(defaultChar)); + descr = (StringDescriptor*) realloc(descr, sizeof(StringDescriptor) + (newCapacity + 1) * sizeof(DefaultChar)); if (descr == NULL) - throw; //std::bad_alloc& e - data = (defaultChar*)(descr + 1); + throw std::bad_alloc(); + data = (DefaultChar*)(descr + 1); descr->capacity = newCapacity; } } diff --git a/library/zstring.h b/library/zstring.h index 00590d4f..9013dd22 100644 --- a/library/zstring.h +++ b/library/zstring.h @@ -7,7 +7,8 @@ #ifndef ZSTRING_H_INCLUDED #define ZSTRING_H_INCLUDED -#include <wx/string.h> +#include <string> + namespace FreeFileSync { @@ -18,6 +19,7 @@ namespace FreeFileSync #endif //FFS_WIN } + #ifdef FFS_WIN #define ZSTRING_WIDE_CHAR //use wide character strings @@ -27,89 +29,93 @@ namespace FreeFileSync #ifdef ZSTRING_CHAR -typedef char defaultChar; +typedef char DefaultChar; #elif defined ZSTRING_WIDE_CHAR -typedef wchar_t defaultChar; +typedef wchar_t DefaultChar; #endif + class Zstring { public: Zstring(); - Zstring(const defaultChar* source); //string is copied: O(length) - Zstring(const defaultChar* source, size_t length); //string is copied: O(length) + Zstring(const DefaultChar* source); //string is copied: O(length) + Zstring(const DefaultChar* source, size_t length); //string is copied: O(length) Zstring(const Zstring& source); //reference-counting => O(1) - Zstring(const wxString& source); //string is copied: O(length) ~Zstring(); - operator const defaultChar*() const; //implicit conversion to C string - operator const wxString() const; //implicit conversion to wxString + operator const DefaultChar*() const; //implicit conversion to C string //wxWidgets functions - bool StartsWith(const defaultChar* begin) const; + bool StartsWith(const DefaultChar* begin) const; bool StartsWith(const Zstring& begin) const; - bool EndsWith(const defaultChar* end) const; + bool EndsWith(const DefaultChar* end) const; bool EndsWith(const Zstring& end) const; #ifdef FFS_WIN - int CmpNoCase(const defaultChar* other) const; + int CmpNoCase(const DefaultChar* other) const; int CmpNoCase(const Zstring& other) const; #endif - int Cmp(const defaultChar* other) const; + int Cmp(const DefaultChar* other) const; int Cmp(const Zstring& other) const; - size_t Replace(const defaultChar* old, const defaultChar* replacement, bool replaceAll = true); - Zstring AfterLast(defaultChar ch) const; - Zstring BeforeLast(defaultChar ch) const; - size_t Find(defaultChar ch, bool fromEnd) const; - bool Matches(const defaultChar* mask) const; + size_t Replace(const DefaultChar* old, const DefaultChar* replacement, bool replaceAll = true); + Zstring AfterLast(DefaultChar ch) const; + Zstring BeforeLast(DefaultChar ch) const; + size_t Find(DefaultChar ch, bool fromEnd) const; + bool Matches(const DefaultChar* mask) const; Zstring& Trim(bool fromRight); //from right or left Zstring& MakeLower(); //std::string functions size_t length() const; - const defaultChar* c_str() const; + const DefaultChar* c_str() const; Zstring substr(size_t pos = 0, size_t len = npos) const; bool empty() const; - int compare(const defaultChar* other) const; + int compare(const DefaultChar* other) const; int compare(const Zstring& other) const; - int compare(const size_t pos1, const size_t n1, const defaultChar* other) const; - size_t find(const defaultChar* str, const size_t pos = 0 ) const; - size_t find(const defaultChar ch, const size_t pos = 0) const; - size_t rfind(const defaultChar ch, size_t pos = npos) const; - Zstring& replace(size_t pos1, size_t n1, const defaultChar* str, size_t n2); + int compare(const size_t pos1, const size_t n1, const DefaultChar* other) const; + size_t find(const DefaultChar* str, const size_t pos = 0 ) const; + size_t find(const DefaultChar ch, const size_t pos = 0) const; + size_t rfind(const DefaultChar ch, size_t pos = npos) const; + Zstring& replace(size_t pos1, size_t n1, const DefaultChar* str, size_t n2); + size_t size() const; Zstring& operator=(const Zstring& source); - Zstring& operator=(const defaultChar* source); + Zstring& operator=(const DefaultChar* source); bool operator==(const Zstring& other) const; - bool operator==(const defaultChar* other) const; + bool operator==(const DefaultChar* other) const; + bool operator!=(const Zstring& other) const; + bool operator!=(const DefaultChar* other) const; + + DefaultChar operator[](const size_t pos) const; Zstring& operator+=(const Zstring& other); - Zstring& operator+=(const defaultChar* other); - Zstring& operator+=(defaultChar ch); + Zstring& operator+=(const DefaultChar* other); + Zstring& operator+=(DefaultChar ch); Zstring operator+(const Zstring& string2) const; - Zstring operator+(const defaultChar* string2) const; - Zstring operator+(const defaultChar ch) const; + Zstring operator+(const DefaultChar* string2) const; + Zstring operator+(const DefaultChar ch) const; static const size_t npos = static_cast<size_t>(-1); private: - void initAndCopy(const defaultChar* source, size_t length); - void incRef(); //support for reference-counting + void initAndCopy(const DefaultChar* source, size_t length); + void incRef() const; //support for reference-counting void decRef(); // void copyBeforeWrite(const size_t capacityNeeded); //and copy-on-write struct StringDescriptor { StringDescriptor(const unsigned int refC, const size_t len, const size_t cap) : refCount(refC), length(len), capacity(cap) {} - unsigned int refCount; + mutable unsigned int refCount; size_t length; size_t capacity; //allocated length without null-termination }; - static void allocate(const unsigned int newRefCount, const size_t newLength, const size_t newCapacity, Zstring::StringDescriptor*& newDescr, defaultChar*& newData); + static void allocate(const unsigned int newRefCount, const size_t newLength, const size_t newCapacity, Zstring::StringDescriptor*& newDescr, DefaultChar*& newData); StringDescriptor* descr; - defaultChar* data; + DefaultChar* data; }; @@ -151,13 +157,13 @@ inline bool defaultIsWhiteSpace(const char ch) { // some compilers (e.g. VC++ 6.0) return true for a call to isspace('\xEA') => exclude char(128) to char(255) - return (ch < 128) && isspace(ch) != 0; + return ((unsigned char)ch < 128) && isspace((unsigned char)ch) != 0; } inline char defaultToLower(const char ch) { - return tolower(ch); + return tolower((unsigned char)ch); //caution: although tolower() has int as input parameter it expects unsigned chars! } #elif defined ZSTRING_WIDE_CHAR @@ -217,20 +223,20 @@ void Zstring::allocate(const unsigned int newRefCount, const size_t newLength, const size_t newCapacity, StringDescriptor*& newDescr, - defaultChar*& newData) + DefaultChar*& newData) { //allocate and set data for new string if (newCapacity) { - newDescr = (StringDescriptor*) malloc( sizeof(StringDescriptor) + (newCapacity + 1) * sizeof(defaultChar)); + newDescr = (StringDescriptor*) malloc( sizeof(StringDescriptor) + (newCapacity + 1) * sizeof(DefaultChar)); if (newDescr == NULL) - throw; //std::bad_alloc& e - newData = (defaultChar*)(newDescr + 1); + throw std::bad_alloc(); + newData = (DefaultChar*)(newDescr + 1); } else { newDescr = (StringDescriptor*) malloc( sizeof(StringDescriptor)); if (newDescr == NULL) - throw; //std::bad_alloc& e + throw std::bad_alloc(); newData = NULL; } @@ -259,14 +265,14 @@ Zstring::Zstring() inline -Zstring::Zstring(const defaultChar* source) +Zstring::Zstring(const DefaultChar* source) { initAndCopy(source, defaultLength(source)); } inline -Zstring::Zstring(const defaultChar* source, size_t length) +Zstring::Zstring(const DefaultChar* source, size_t length) { initAndCopy(source, length); } @@ -282,13 +288,6 @@ Zstring::Zstring(const Zstring& source) inline -Zstring::Zstring(const wxString& source) -{ - initAndCopy(source.c_str(), source.length()); -} - - -inline Zstring::~Zstring() { decRef(); @@ -303,17 +302,17 @@ size_t getCapacityToAllocate(const size_t length) inline -void Zstring::initAndCopy(const defaultChar* source, size_t length) +void Zstring::initAndCopy(const DefaultChar* source, size_t length) { const size_t newCapacity = getCapacityToAllocate(length); allocate(1, length, newCapacity, descr, data); - memcpy(data, source, length * sizeof(defaultChar)); + memcpy(data, source, length * sizeof(DefaultChar)); data[length] = 0; } inline -void Zstring::incRef() +void Zstring::incRef() const { assert(descr); ++descr->refCount; @@ -337,7 +336,7 @@ void Zstring::decRef() #ifdef FFS_WIN inline -int Zstring::CmpNoCase(const defaultChar* other) const +int Zstring::CmpNoCase(const DefaultChar* other) const { return FreeFileSync::compareStringsWin32(c_str(), other); //way faster than wxString::CmpNoCase()!! } @@ -352,7 +351,7 @@ int Zstring::CmpNoCase(const Zstring& other) const inline -Zstring::operator const defaultChar*() const +Zstring::operator const DefaultChar*() const { return c_str(); } @@ -361,19 +360,17 @@ Zstring::operator const defaultChar*() const inline Zstring& Zstring::operator=(const Zstring& source) { - if (this != &source) - { - decRef(); - descr = source.descr; - data = source.data; - incRef(); - } + source.incRef(); //implicitly handle case "this == &source" and avoid this check + decRef(); // + descr = source.descr; + data = source.data; + return *this; } inline -size_t Zstring::Find(defaultChar ch, bool fromEnd) const +size_t Zstring::Find(DefaultChar ch, bool fromEnd) const { if (fromEnd) return rfind(ch, npos); @@ -385,7 +382,7 @@ size_t Zstring::Find(defaultChar ch, bool fromEnd) const // get all characters after the last occurence of ch // (returns the whole string if ch not found) inline -Zstring Zstring::AfterLast(defaultChar ch) const +Zstring Zstring::AfterLast(DefaultChar ch) const { size_t pos = rfind(ch, npos); if (pos == npos ) @@ -398,7 +395,7 @@ Zstring Zstring::AfterLast(defaultChar ch) const // get all characters before the last occurence of ch // (returns empty string if ch not found) inline -Zstring Zstring::BeforeLast(defaultChar ch) const +Zstring Zstring::BeforeLast(DefaultChar ch) const { size_t pos = rfind(ch, npos); @@ -410,7 +407,7 @@ Zstring Zstring::BeforeLast(defaultChar ch) const inline -bool Zstring::StartsWith(const defaultChar* begin) const +bool Zstring::StartsWith(const DefaultChar* begin) const { const size_t beginLength = defaultLength(begin); if (length() < beginLength) @@ -430,7 +427,7 @@ bool Zstring::StartsWith(const Zstring& begin) const inline -bool Zstring::EndsWith(const defaultChar* end) const +bool Zstring::EndsWith(const DefaultChar* end) const { const size_t thisLength = length(); const size_t endLength = defaultLength(end); @@ -452,57 +449,64 @@ bool Zstring::EndsWith(const Zstring& end) const inline -size_t Zstring::find(const defaultChar* str, const size_t pos) const +size_t Zstring::find(const DefaultChar* str, const size_t pos) const { assert(pos <= length()); - const defaultChar* thisStr = c_str(); - const defaultChar* found = defaultStrFind(thisStr + pos, str); + const DefaultChar* thisStr = c_str(); + const DefaultChar* found = defaultStrFind(thisStr + pos, str); return found == NULL ? npos : found - thisStr; } inline -size_t Zstring::find(const defaultChar ch, const size_t pos) const +size_t Zstring::find(const DefaultChar ch, const size_t pos) const { assert(pos <= length()); - const defaultChar* thisStr = c_str(); - const defaultChar* found = defaultStrFind(thisStr + pos, ch); + const DefaultChar* thisStr = c_str(); + const DefaultChar* found = defaultStrFind(thisStr + pos, ch); return found == NULL ? npos : found - thisStr; } inline -Zstring::operator const wxString() const +int Zstring::Cmp(const DefaultChar* other) const { - return wxString(c_str()); + return compare(other); } inline -int Zstring::Cmp(const defaultChar* other) const +int Zstring::Cmp(const Zstring& other) const { - return compare(other); + return defaultCompare(c_str(), other.c_str()); //overload using strcmp(char*, char*) should be fastest! } inline -int Zstring::Cmp(const Zstring& other) const +bool Zstring::operator==(const Zstring& other) const { - return defaultCompare(c_str(), other.c_str()); //overload using strcmp(char*, char*) should be fastest! + return length() != other.length() ? false : defaultCompare(c_str(), other.c_str()) == 0; } inline -bool Zstring::operator==(const Zstring& other) const +bool Zstring::operator==(const DefaultChar* other) const { - return defaultCompare(c_str(), other.c_str()) == 0; //overload using strcmp(char*, char*) should be fastest! + return defaultCompare(c_str(), other) == 0; //overload using strcmp(char*, char*) should be fastest! } inline -bool Zstring::operator==(const defaultChar* other) const +bool Zstring::operator!=(const Zstring& other) const { - return compare(other) == 0; + return length() != other.length() ? true: defaultCompare(c_str(), other.c_str()) != 0; +} + + +inline +bool Zstring::operator!=(const DefaultChar* other) const +{ + return defaultCompare(c_str(), other) != 0; //overload using strcmp(char*, char*) should be fastest! } @@ -514,14 +518,14 @@ int Zstring::compare(const Zstring& other) const inline -int Zstring::compare(const defaultChar* other) const +int Zstring::compare(const DefaultChar* other) const { return defaultCompare(c_str(), other); //overload using strcmp(char*, char*) should be fastest! } inline -int Zstring::compare(const size_t pos1, const size_t n1, const defaultChar* other) const +int Zstring::compare(const size_t pos1, const size_t n1, const DefaultChar* other) const { assert(length() - pos1 >= n1); return defaultCompare(c_str() + pos1, other, n1); @@ -536,7 +540,14 @@ size_t Zstring::length() const inline -const defaultChar* Zstring::c_str() const +size_t Zstring::size() const +{ + return descr->length; +} + + +inline +const DefaultChar* Zstring::c_str() const { if (length()) return data; @@ -557,6 +568,14 @@ bool Zstring::empty() const inline +DefaultChar Zstring::operator[](const size_t pos) const +{ + assert(pos < length()); + return data[pos]; +} + + +inline Zstring Zstring::operator+(const Zstring& string2) const { return Zstring(*this)+=string2; @@ -564,14 +583,14 @@ Zstring Zstring::operator+(const Zstring& string2) const inline -Zstring Zstring::operator+(const defaultChar* string2) const +Zstring Zstring::operator+(const DefaultChar* string2) const { return Zstring(*this)+=string2; } inline -Zstring Zstring::operator+(const defaultChar ch) const +Zstring Zstring::operator+(const DefaultChar ch) const { return Zstring(*this)+=ch; } |