diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 16:58:10 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 16:58:10 +0200 |
commit | fefe20351d0720683990b666584b6879c90bd37d (patch) | |
tree | 8ab90520ae2123ac84293b0f9cec006317e5fc01 /library | |
parent | 1.18 (diff) | |
download | FreeFileSync-fefe20351d0720683990b666584b6879c90bd37d.tar.gz FreeFileSync-fefe20351d0720683990b666584b6879c90bd37d.tar.bz2 FreeFileSync-fefe20351d0720683990b666584b6879c90bd37d.zip |
1.19
Diffstat (limited to 'library')
-rw-r--r-- | library/CustomGrid.cpp | 564 | ||||
-rw-r--r-- | library/CustomGrid.h | 113 | ||||
-rw-r--r-- | library/customButton.cpp | 3 | ||||
-rw-r--r-- | library/fileHandling.cpp | 46 | ||||
-rw-r--r-- | library/filter.cpp | 131 | ||||
-rw-r--r-- | library/filter.h | 22 | ||||
-rw-r--r-- | library/localization.cpp | 11 | ||||
-rw-r--r-- | library/processXml.cpp | 92 | ||||
-rw-r--r-- | library/processXml.h | 31 | ||||
-rw-r--r-- | library/resources.cpp | 52 | ||||
-rw-r--r-- | library/resources.h | 51 | ||||
-rw-r--r-- | library/statusHandler.cpp | 3 | ||||
-rw-r--r-- | library/statusHandler.h | 4 | ||||
-rw-r--r-- | library/zstring.cpp | 7 | ||||
-rw-r--r-- | library/zstring.h | 1 |
15 files changed, 830 insertions, 301 deletions
diff --git a/library/CustomGrid.cpp b/library/CustomGrid.cpp index faa75b2d..048bc5e0 100644 --- a/library/CustomGrid.cpp +++ b/library/CustomGrid.cpp @@ -41,11 +41,14 @@ class CustomGridTable : public wxGridTableBase public: CustomGridTable(int initialRows = 0, int initialCols = 0) : //note: initialRows/initialCols MUST match with GetNumberRows()/GetNumberCols() at initialization!!! wxGridTableBase(), - COLOR_BLUE( 80, 110, 255), - COLOR_GREY( 212, 208, 200), - COLOR_LIGHT_RED( 235, 57, 61), - COLOR_LIGHT_BLUE( 63, 206, 233), - COLOR_LIGHT_GREEN(54, 218, 2), + COLOR_BLUE( 80, 110, 255), + COLOR_GREY( 212, 208, 200), + COLOR_CMP_RED( 249, 163, 165), + COLOR_CMP_BLUE( 144, 232, 246), + COLOR_CMP_GREEN( 147, 253, 159), + COLOR_SYNC_BLUE( 201, 203, 247), + COLOR_SYNC_GREEN(197, 248, 190), + COLOR_YELLOW( 247, 252, 62), gridDataView(NULL), lastNrRows(initialRows), lastNrCols(initialCols) {} @@ -54,7 +57,7 @@ public: virtual ~CustomGridTable() {} - void setGridDataTable(GridView* gridDataView) + void setGridDataTable(const GridView* gridDataView) { this->gridDataView = gridDataView; } @@ -185,17 +188,20 @@ public: protected: const wxColour COLOR_BLUE; const wxColour COLOR_GREY; - const wxColour COLOR_LIGHT_RED; - const wxColour COLOR_LIGHT_BLUE; - const wxColour COLOR_LIGHT_GREEN; + const wxColour COLOR_CMP_RED; + const wxColour COLOR_CMP_BLUE; + const wxColour COLOR_CMP_GREEN; + const wxColour COLOR_SYNC_BLUE; + const wxColour COLOR_SYNC_GREEN; + const wxColour COLOR_YELLOW; const GridView* gridDataView; //(very fast) access to underlying grid data :) private: virtual const wxColour& getRowColor(int row) = 0; //rows that are filtered out are shown in different color - int lastNrRows; - int lastNrCols; + int lastNrRows; + int lastNrCols; }; @@ -246,8 +252,8 @@ public: { switch (getTypeAtPos(col)) { - case xmlAccess::FULL_NAME: - return gridLine->fileDescrLeft.fullName.c_str(); + case xmlAccess::FULL_PATH: + return wxString(gridLine->fileDescrLeft.fullName.c_str()); case xmlAccess::FILENAME: return wxEmptyString; case xmlAccess::REL_PATH: @@ -264,8 +270,8 @@ public: { switch (getTypeAtPos(col)) { - case xmlAccess::FULL_NAME: - return gridLine->fileDescrLeft.fullName.c_str(); + case xmlAccess::FULL_PATH: + return wxString(gridLine->fileDescrLeft.fullName.c_str()).BeforeLast(GlobalResources::FILE_NAME_SEPARATOR); case xmlAccess::FILENAME: //filename return wxString(gridLine->fileDescrLeft.relativeName.c_str()).AfterLast(GlobalResources::FILE_NAME_SEPARATOR); case xmlAccess::REL_PATH: //relative path @@ -275,7 +281,7 @@ public: case xmlAccess::SIZE: //file size return globalFunctions::includeNumberSeparator(gridLine->fileDescrLeft.fileSize.ToString()); case xmlAccess::DATE: //date - return FreeFileSync::utcTimeToLocalString(gridLine->fileDescrLeft.lastWriteTimeRaw); + return FreeFileSync::utcTimeToLocalString(gridLine->fileDescrLeft.lastWriteTimeRaw, gridLine->fileDescrLeft.fullName); } } } @@ -315,8 +321,8 @@ public: { switch (getTypeAtPos(col)) { - case xmlAccess::FULL_NAME: - return gridLine->fileDescrRight.fullName.c_str(); + case xmlAccess::FULL_PATH: + return wxString(gridLine->fileDescrRight.fullName.c_str()); case xmlAccess::FILENAME: //filename return wxEmptyString; case xmlAccess::REL_PATH: //relative path @@ -333,8 +339,8 @@ public: { switch (getTypeAtPos(col)) { - case xmlAccess::FULL_NAME: - return gridLine->fileDescrRight.fullName.c_str(); + case xmlAccess::FULL_PATH: + return wxString(gridLine->fileDescrRight.fullName.c_str()).BeforeLast(GlobalResources::FILE_NAME_SEPARATOR); case xmlAccess::FILENAME: //filename return wxString(gridLine->fileDescrRight.relativeName.c_str()).AfterLast(GlobalResources::FILE_NAME_SEPARATOR); case xmlAccess::REL_PATH: //relative path @@ -344,7 +350,7 @@ public: case xmlAccess::SIZE: //file size return globalFunctions::includeNumberSeparator(gridLine->fileDescrRight.fileSize.ToString()); case xmlAccess::DATE: //date - return FreeFileSync::utcTimeToLocalString(gridLine->fileDescrRight.lastWriteTimeRaw); + return FreeFileSync::utcTimeToLocalString(gridLine->fileDescrRight.lastWriteTimeRaw, gridLine->fileDescrRight.fullName); } } } @@ -376,7 +382,9 @@ class CustomGridTableMiddle : public CustomGridTable { public: //middle grid is created (first wxWidgets internal call to GetNumberCols()) with one column - CustomGridTableMiddle() : CustomGridTable(0, GetNumberCols()) {} //attention: static binding to virtual GetNumberCols() in a Constructor! + CustomGridTableMiddle() : + CustomGridTable(0, GetNumberCols()), //attention: static binding to virtual GetNumberCols() in a Constructor! + syncPreviewActive(false) {} virtual int GetNumberCols() { @@ -388,35 +396,21 @@ public: return wxEmptyString; } - virtual wxString GetValue(int row, int col) { - const FileCompareLine* gridLine = getRawData(row); - if (gridLine) - { - 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; } + void enableSyncPreview(bool value) + { + syncPreviewActive = value; + } + + bool syncPreviewIsActive() const + { + return syncPreviewActive; + } + private: virtual const wxColour& getRowColor(int row) //rows that are filtered out are shown in different color { @@ -426,23 +420,46 @@ private: //mark filtered rows if (!gridLine->selectedForSynchronization) return COLOR_BLUE; - else + + if (syncPreviewActive) //synchronization preview + { + switch (gridLine->direction) + { + case SYNC_DIR_LEFT: + return COLOR_SYNC_BLUE; + case SYNC_DIR_RIGHT: + return COLOR_SYNC_GREEN; + case SYNC_DIR_NONE: + return *wxWHITE; + case SYNC_UNRESOLVED_CONFLICT: + return COLOR_YELLOW; + } + } + else //comparison results view + { switch (gridLine->cmpResult) { case FILE_LEFT_SIDE_ONLY: case FILE_RIGHT_SIDE_ONLY: - return COLOR_LIGHT_GREEN; + return COLOR_CMP_GREEN; case FILE_LEFT_NEWER: case FILE_RIGHT_NEWER: - return COLOR_LIGHT_BLUE; + return COLOR_CMP_BLUE; case FILE_DIFFERENT: - return COLOR_LIGHT_RED; - default: + return COLOR_CMP_RED; + case FILE_EQUAL: return *wxWHITE; + case FILE_CONFLICT: + return COLOR_YELLOW; } + } } + + //fallback return *wxWHITE; } + + bool syncPreviewActive; //determines wheter grid shall show compare result or sync preview }; //######################################################################################################## @@ -748,6 +765,59 @@ void CustomGrid::DrawColLabel(wxDC& dc, int col) dc.DrawBitmap(*sortMarker, GetColRight(col) - 16 - 2, 2, true); //respect 2-pixel border } + +std::set<int> CustomGrid::getAllSelectedRows() const +{ + std::set<int> output; + + const wxArrayInt selectedRows = this->GetSelectedRows(); + if (!selectedRows.IsEmpty()) + { + for (unsigned int i = 0; i < selectedRows.GetCount(); ++i) + output.insert(selectedRows[i]); + } + + if (!this->GetSelectedCols().IsEmpty()) //if a column is selected this is means all rows are marked for deletion + { + for (int k = 0; k < const_cast<CustomGrid*>(this)->GetNumberRows(); ++k) //messy wxGrid implementation... + output.insert(k); + } + + const wxGridCellCoordsArray singlySelected = this->GetSelectedCells(); + if (!singlySelected.IsEmpty()) + { + for (unsigned int k = 0; k < singlySelected.GetCount(); ++k) + output.insert(singlySelected[k].GetRow()); + } + + const wxGridCellCoordsArray tmpArrayTop = this->GetSelectionBlockTopLeft(); + if (!tmpArrayTop.IsEmpty()) + { + wxGridCellCoordsArray tmpArrayBottom = this->GetSelectionBlockBottomRight(); + + unsigned int arrayCount = tmpArrayTop.GetCount(); + + if (arrayCount == tmpArrayBottom.GetCount()) + { + for (unsigned int i = 0; i < arrayCount; ++i) + { + const int rowTop = tmpArrayTop[i].GetRow(); + const int rowBottom = tmpArrayBottom[i].GetRow(); + + for (int k = rowTop; k <= rowBottom; ++k) + output.insert(k); + } + } + } + + //some exception: also add current cursor row to selection if there are no others... hopefully improving usability + if (output.empty() && this->isLeadGrid()) + output.insert(const_cast<CustomGrid*>(this)->GetCursorRow()); //messy wxGrid implementation... + + return output; +} + + //############################################################################################ //CustomGrid specializations @@ -837,6 +907,26 @@ private: const CustomGridTableRim* const m_gridDataTable; }; +//---------------------------------------------------------------------------------------- + + +void CustomGridRim::initSettings(const bool showFileIcons, + CustomGrid* gridLeft, + CustomGrid* gridRight, + CustomGrid* gridMiddle, + const GridView* gridDataView) +{ + //these grids will scroll together + m_gridLeft = gridLeft; + m_gridRight = gridRight; + m_gridMiddle = gridMiddle; + + //set underlying grid data + assert(gridDataTable); + gridDataTable->setGridDataTable(gridDataView); + + enableFileIcons(showFileIcons); +} void CustomGridRim::updateGridSizes() @@ -851,7 +941,7 @@ xmlAccess::ColumnAttributes CustomGridRim::getDefaultColumnAttributes() xmlAccess::ColumnAttributes defaultColumnSettings; xmlAccess::ColumnAttrib newEntry; - newEntry.type = xmlAccess::FULL_NAME; + newEntry.type = xmlAccess::FULL_PATH; newEntry.visible = false; newEntry.position = 0; newEntry.width = 150; @@ -990,8 +1080,8 @@ wxString CustomGridRim::getTypeName(xmlAccess::ColumnTypes colType) { switch (colType) { - case xmlAccess::FULL_NAME: - return _("Full name"); + case xmlAccess::FULL_PATH: + return _("Full path"); case xmlAccess::FILENAME: return _("Filename"); case xmlAccess::REL_PATH: @@ -1002,13 +1092,14 @@ wxString CustomGridRim::getTypeName(xmlAccess::ColumnTypes colType) return _("Size"); case xmlAccess::DATE: return _("Date"); - default: - return wxEmptyString; } -} + return wxEmptyString; //dummy +} //---------------------------------------------------------------------------------------- + + CustomGridLeft::CustomGridLeft(wxWindow *parent, wxWindowID id, const wxPoint& pos, @@ -1029,25 +1120,14 @@ bool CustomGridLeft::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectio } -void CustomGridLeft::initSettings(const bool showFileIcons, - CustomGrid* gridLeft, - CustomGrid* gridRight, - CustomGrid* gridMiddle, - GridView* gridDataView) +void CustomGridLeft::enableFileIcons(const bool value) { - //these grids will scroll together - m_gridLeft = gridLeft; - m_gridRight = gridRight; - m_gridMiddle = gridMiddle; - - //set underlying grid data - assert(gridDataTable); - gridDataTable->setGridDataTable(gridDataView); - - if (showFileIcons) + if (value) SetDefaultRenderer(new GridCellRenderer<true, true>(gridDataTable)); //SetDefaultRenderer takes ownership! else SetDefaultRenderer(new GridCellRenderer<true, false>(gridDataTable)); + + Refresh(); } @@ -1085,25 +1165,14 @@ bool CustomGridRight::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelecti } -void CustomGridRight::initSettings(const bool showFileIcons, - CustomGrid* gridLeft, - CustomGrid* gridRight, - CustomGrid* gridMiddle, - GridView* gridDataView) +void CustomGridRight::enableFileIcons(const bool value) { - //these grids will scroll together - m_gridLeft = gridLeft; - m_gridRight = gridRight; - m_gridMiddle = gridMiddle; - - //set underlying grid data - assert(gridDataTable); - gridDataTable->setGridDataTable(gridDataView); - - if (showFileIcons) + if (value) SetDefaultRenderer(new GridCellRenderer<false, true>(gridDataTable)); //SetDefaultRenderer takes ownership! else SetDefaultRenderer(new GridCellRenderer<false, false>(gridDataTable)); + + Refresh(); } @@ -1123,6 +1192,19 @@ void CustomGridRight::DoPrepareDC(wxDC& dc) //---------------------------------------------------------------------------------------- +//define new event types +const wxEventType FFS_CHECK_ROWS_EVENT = wxNewEventType(); //attention! do NOT place in header to keep (generated) id unique! +const wxEventType FFS_SYNC_DIRECTION_EVENT = wxNewEventType(); + +const int CHECK_BOX_IMAGE = 11; //width of checkbox image +const int CHECK_BOX_WIDTH = CHECK_BOX_IMAGE + 3; //width of first block + +// cell: +// ---------------------------------- +// | checkbox | left | middle | right| +// ---------------------------------- + + CustomGridMiddle::CustomGridMiddle(wxWindow *parent, wxWindowID id, const wxPoint& pos, @@ -1130,25 +1212,155 @@ CustomGridMiddle::CustomGridMiddle(wxWindow *parent, long style, const wxString& name) : CustomGrid(parent, id, pos, size, style, name), + selectionRowBegin(-1), + selectionPos(BLOCKPOS_CHECK_BOX), + highlightedRow(-1), + highlightedPos(BLOCKPOS_CHECK_BOX), gridDataTable(NULL) { - const wxString header = _("Legend"); - wxString toolTip = header + wxT("\n") + - wxString().Pad(header.Len(), wxChar('-')) + wxT("\n") + - _("<| file on left side only\n") + - _("|> file on right side only\n") + - _("<< left file is newer\n") + - _(">> right file is newer\n") + - _("!= files are different\n") + - _("== files are equal\n\n"); - GetGridWindow()->SetToolTip(toolTip); + //connect events for dynamic selection of sync direction + GetGridWindow()->Connect(wxEVT_MOTION, wxMouseEventHandler(CustomGridMiddle::OnMouseMovement), NULL, this); + + GetGridWindow()->Connect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(CustomGridMiddle::OnLeaveWindow), NULL, this); + GetGridWindow()->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(CustomGridMiddle::OnLeftMouseUp), NULL, this); + GetGridWindow()->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(CustomGridMiddle::OnLeftMouseDown), NULL, this); +} + + +void CustomGridMiddle::OnMouseMovement(wxMouseEvent& event) +{ + const int highlightedRowOld = highlightedRow; + + if (selectionRowBegin == -1) //change highlightning only if currently not dragging mouse + { + highlightedRow = mousePosToRow(event.GetPosition(), &highlightedPos); + if (highlightedRow >= 0) RefreshRow(highlightedRow); + if ( highlightedRowOld >= 0 && + highlightedRow != highlightedRowOld) + RefreshRow(highlightedRowOld); + } + + event.Skip(); +} + + +void CustomGridMiddle::RefreshRow(int row) +{ + wxRect rectScrolled(CellToRect(row, 0)); + CalcScrolledPosition(rectScrolled.x, rectScrolled.y, &rectScrolled.x, &rectScrolled.y); + + GetGridWindow()->Refresh(false, &rectScrolled); //note: CellToRect() and YToRow work on m_gridWindow NOT on the whole grid! +} + + +void CustomGridMiddle::OnLeaveWindow(wxMouseEvent& event) +{ + highlightedRow = -1; + highlightedPos = BLOCKPOS_CHECK_BOX; + Refresh(); +} + + +void CustomGridMiddle::OnLeftMouseDown(wxMouseEvent& event) +{ + selectionRowBegin = mousePosToRow(event.GetPosition(), &selectionPos); + event.Skip(); +} + + +void CustomGridMiddle::OnLeftMouseUp(wxMouseEvent& event) +{ + const int rowEndFiltering = mousePosToRow(event.GetPosition()); + + if (0 <= selectionRowBegin && 0 <= rowEndFiltering) + { + switch (selectionPos) + { + case BLOCKPOS_CHECK_BOX: + { + //create a custom event + FFSCheckRowsEvent evt(selectionRowBegin, rowEndFiltering); + AddPendingEvent(evt); + } + break; + case BLOCKPOS_LEFT: + { + //create a custom event + FFSSyncDirectionEvent evt(selectionRowBegin, rowEndFiltering, SYNC_DIR_LEFT); + AddPendingEvent(evt); + } + break; + case BLOCKPOS_MIDDLE: + { + //create a custom event + FFSSyncDirectionEvent evt(selectionRowBegin, rowEndFiltering, SYNC_DIR_NONE); + AddPendingEvent(evt); + } + break; + case BLOCKPOS_RIGHT: + { + //create a custom event + FFSSyncDirectionEvent evt(selectionRowBegin, rowEndFiltering, SYNC_DIR_RIGHT); + AddPendingEvent(evt); + } + break; + } + } + selectionRowBegin = -1; + selectionPos = BLOCKPOS_CHECK_BOX; + + ClearSelection(); + event.Skip(); +} + + +int CustomGridMiddle::mousePosToRow(const wxPoint pos, BlockPosition* block) +{ + int row = -1; + int x = -1; + int y = -1; + CalcUnscrolledPosition( pos.x, pos.y, &x, &y ); + if (x >= 0 && y >= 0) + { + row = YToRow(y); + + //determine blockposition within cell (optional) + if (block) + { + *block = BLOCKPOS_CHECK_BOX; //default + if (gridDataTable->syncPreviewIsActive() && + row >= 0) + { + // cell: + // ---------------------------------- + // | checkbox | left | middle | right| + // ---------------------------------- + + const wxRect rect = CellToRect(row, 0); + if (rect.GetWidth() > CHECK_BOX_WIDTH) + { + const double blockWidth = (rect.GetWidth() - CHECK_BOX_WIDTH) / 3.0; + if (rect.GetX() + CHECK_BOX_WIDTH <= x && x < rect.GetX() + rect.GetWidth()) + { + if (x - (rect.GetX() + CHECK_BOX_WIDTH) < blockWidth) + *block = BLOCKPOS_LEFT; + else if (x - (rect.GetX() + CHECK_BOX_WIDTH) < 2 * blockWidth) + *block = BLOCKPOS_MIDDLE; + else + *block = BLOCKPOS_RIGHT; + } + } + } + } + } + return row; } void CustomGridMiddle::initSettings(CustomGrid* gridLeft, CustomGrid* gridRight, CustomGrid* gridMiddle, - FreeFileSync::GridView* gridDataView) + const FreeFileSync::GridView* gridDataView) { //these grids will scroll together m_gridLeft = gridLeft; @@ -1174,6 +1386,40 @@ void CustomGridMiddle::SetScrollbar(int orientation, int position, int thumbSize } #endif + +void CustomGridMiddle::enableSyncPreview(bool value) +{ + assert(gridDataTable); + gridDataTable->enableSyncPreview(value); + + //update legend + wxString toolTip; + + if (gridDataTable->syncPreviewIsActive()) //synchronization preview + { + const wxString header = _("Synchronization Preview"); + toolTip = header + wxT("\n") + wxString().Pad(header.Len(), wxChar('-')) + wxT("\n"); + toolTip += wxString(_("<- copy to left side\n")) + + _("-> copy to right side\n") + + wxT(" ")+ _("- do not copy\n") + + _("flash conflict\n"); + } + else //compare results view + { + const wxString header = _("Comparison Result"); + toolTip = header + wxT("\n") + wxString().Pad(header.Len(), wxChar('-')) + wxT("\n"); + toolTip += wxString(_("<| file on left side only\n")) + + _("|> file on right side only\n") + + _("<< left file is newer\n") + + _(">> right file is newer\n") + + _("!= files are different\n") + + _("== files are equal\n") + + _("flash conflict\n"); + } + GetGridColLabelWindow()->SetToolTip(toolTip); +} + + void CustomGridMiddle::updateGridSizes() { assert(gridDataTable); @@ -1184,7 +1430,7 @@ void CustomGridMiddle::updateGridSizes() class GridCellRendererMiddle : public wxGridCellStringRenderer { public: - GridCellRendererMiddle(CustomGridTable* gridDataTable) : m_gridDataTable(gridDataTable) {}; + GridCellRendererMiddle(const CustomGridMiddle* middleGrid) : m_gridMiddle(middleGrid) {}; virtual void Draw(wxGrid& grid, @@ -1195,36 +1441,112 @@ public: bool isSelected) { //retrieve grid data - const FileCompareLine* rowData = m_gridDataTable->getRawData(row); - if (!rowData) //no valid row + const FileCompareLine* const rowData = m_gridMiddle->gridDataTable->getRawData(row); + if (rowData) //no valid row { - wxGridCellStringRenderer::Draw(grid, attr, dc, rect, row, col, isSelected); - return; - } + if (rect.GetWidth() > CHECK_BOX_WIDTH) + { + wxRect rectShrinked(rect); - const int shift = std::min(11 + 3, rect.GetWidth()); //11 is width of checkbox image + //clean first block of rect that will receive image of checkbox + rectShrinked.SetWidth(CHECK_BOX_WIDTH); + wxGridCellRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected); - wxRect rectShrinked(rect); + //print image into first block + rectShrinked.SetX(rect.GetX() + 1); + bool selected = rowData->selectedForSynchronization; - //clean first block of rect that will receive image of checkbox - rectShrinked.SetWidth(shift); - wxGridCellRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected); + //HIGHLIGHTNING: + if ( row == m_gridMiddle->highlightedRow && + m_gridMiddle->highlightedPos == CustomGridMiddle::BLOCKPOS_CHECK_BOX) + selected = !selected; - //print image into first block - rectShrinked.SetX(rect.GetX() + 1); - if (rowData->selectedForSynchronization) - dc.DrawLabel(wxEmptyString, *globalResource.bitmapCheckBoxTrue, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); - else - dc.DrawLabel(wxEmptyString, *globalResource.bitmapCheckBoxFalse, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + if (selected) + dc.DrawLabel(wxEmptyString, *globalResource.bitmapCheckBoxTrue, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + else + 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(rect.GetX() + shift); - wxGridCellStringRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected); + //clean remaining block of rect that will receive image of checkbox/directions + rectShrinked.SetWidth(rect.GetWidth() - CHECK_BOX_WIDTH); + rectShrinked.SetX(rect.GetX() + CHECK_BOX_WIDTH); + wxGridCellRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected); + + //print remaining block + if (m_gridMiddle->gridDataTable->syncPreviewIsActive()) //synchronization preview + { + //print sync direction into second block + + //HIGHLIGHTNING: + if (row == m_gridMiddle->highlightedRow && m_gridMiddle->highlightedPos != CustomGridMiddle::BLOCKPOS_CHECK_BOX) + switch (m_gridMiddle->highlightedPos) + { + case CustomGridMiddle::BLOCKPOS_CHECK_BOX: + break; + case CustomGridMiddle::BLOCKPOS_LEFT: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapSyncDirLeftSmall, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + break; + case CustomGridMiddle::BLOCKPOS_MIDDLE: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapSyncDirNoneSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case CustomGridMiddle::BLOCKPOS_RIGHT: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapSyncDirRightSmall, rectShrinked, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); + break; + } + else //default + switch (rowData->direction) + { + case SYNC_DIR_LEFT: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapSyncDirLeftSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case SYNC_DIR_RIGHT: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapSyncDirRightSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case SYNC_DIR_NONE: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapSyncDirNoneSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case SYNC_UNRESOLVED_CONFLICT: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapConflictSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + } + } + else //comparison results view + { + switch (rowData->cmpResult) + { + case FILE_LEFT_SIDE_ONLY: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapLeftOnlySmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case FILE_RIGHT_SIDE_ONLY: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapRightOnlySmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case FILE_LEFT_NEWER: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapLeftNewerSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case FILE_RIGHT_NEWER: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapRightNewerSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case FILE_DIFFERENT: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapDifferentSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case FILE_EQUAL: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapEqualSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case FILE_CONFLICT: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapConflictSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + } + } + + return; + } + } + + //fallback + wxGridCellStringRenderer::Draw(grid, attr, dc, rect, row, col, isSelected); } private: - const CustomGridTable* const m_gridDataTable; + const CustomGridMiddle* const m_gridMiddle; }; @@ -1234,7 +1556,7 @@ bool CustomGridMiddle::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelect 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 GridCellRendererMiddle(gridDataTable)); //SetDefaultRenderer takes ownership! + SetDefaultRenderer(new GridCellRendererMiddle(this)); //SetDefaultRenderer takes ownership! return true; } diff --git a/library/CustomGrid.h b/library/CustomGrid.h index 802db231..89ec39d0 100644 --- a/library/CustomGrid.h +++ b/library/CustomGrid.h @@ -10,6 +10,7 @@ class CustomGridTable; class CustomGridTableRim; class CustomGridTableMiddle; +class GridCellRendererMiddle; namespace FreeFileSync { @@ -44,6 +45,8 @@ public: virtual void DrawColLabel(wxDC& dc, int col); + std::set<int> getAllSelectedRows() const; + //set sort direction indicator on UI void setSortMarker(const int sortColumn, const wxBitmap* bitmap = &wxNullBitmap); @@ -79,6 +82,12 @@ public: ~CustomGridRim() {} + void initSettings(const bool showFileIcons, //workaround: though this coding better belongs into a constructor + CustomGrid* gridLeft, //this is not possible due to source code generation (information not available at time of construction) + CustomGrid* gridRight, + CustomGrid* gridMiddle, + const FreeFileSync::GridView* gridDataView); + //notify wxGrid that underlying table size has changed void updateGridSizes(); @@ -88,9 +97,10 @@ public: void setColumnAttributes(const xmlAccess::ColumnAttributes& attr); xmlAccess::ColumnTypes getTypeAtPos(unsigned pos) const; - static wxString getTypeName(xmlAccess::ColumnTypes colType); + virtual void enableFileIcons(const bool value) = 0; + protected: CustomGridTableRim* gridDataTable; @@ -113,11 +123,7 @@ public: virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells); - void initSettings(const bool showFileIcons, //workaround: though this coding better belongs into a constructor - CustomGrid* gridLeft, //this is not possible due to source code generation (information not available at time of construction) - CustomGrid* gridRight, - CustomGrid* gridMiddle, - FreeFileSync::GridView* gridDataView); + virtual void enableFileIcons(const bool value); //this method is called when grid view changes: useful for parallel updating of multiple grids virtual void DoPrepareDC(wxDC& dc); @@ -138,11 +144,7 @@ public: virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells); - void initSettings(const bool showFileIcons, //workaround: though this coding better belongs into a constructor - CustomGrid* gridLeft, //this is not possible due to source code generation (information not available at time of construction) - CustomGrid* gridRight, - CustomGrid* gridMiddle, - FreeFileSync::GridView* gridDataView); + virtual void enableFileIcons(const bool value); //this method is called when grid view changes: useful for parallel updating of multiple grids virtual void DoPrepareDC(wxDC& dc); @@ -151,6 +153,8 @@ public: class CustomGridMiddle : public CustomGrid { + friend class GridCellRendererMiddle; + public: CustomGridMiddle(wxWindow *parent, wxWindowID id, @@ -166,7 +170,9 @@ public: void initSettings(CustomGrid* gridLeft, //workaround: though this coding better belongs into a constructor CustomGrid* gridRight, //this is not possible due to source code generation (information not available at time of construction) CustomGrid* gridMiddle, - FreeFileSync::GridView* gridDataView); + const FreeFileSync::GridView* gridDataView); + + void enableSyncPreview(bool value); //notify wxGrid that underlying table size has changed void updateGridSizes(); @@ -179,7 +185,90 @@ public: virtual void DoPrepareDC(wxDC& dc); private: + void OnMouseMovement(wxMouseEvent& event); + void OnLeaveWindow(wxMouseEvent& event); + void OnLeftMouseDown(wxMouseEvent& event); + void OnLeftMouseUp(wxMouseEvent& event); + + //small helper methods + void RefreshRow(int row); + enum BlockPosition //each cell can be divided into four blocks concerning mouse selections + { + BLOCKPOS_CHECK_BOX, + BLOCKPOS_LEFT, + BLOCKPOS_MIDDLE, + BLOCKPOS_RIGHT + }; + int mousePosToRow(const wxPoint pos, BlockPosition* block = NULL); + + //variables for selecting sync direction + int selectionRowBegin; + BlockPosition selectionPos; + + //variables for highlightning on mouse-over + int highlightedRow; + BlockPosition highlightedPos; + CustomGridTableMiddle* gridDataTable; }; +//custom events for middle grid: + +//-------------------------------------------------------------------------------------------- +//(UN-)CHECKING ROWS FROM SYNCHRONIZATION + +extern const wxEventType FFS_CHECK_ROWS_EVENT; //define new event type + +class FFSCheckRowsEvent : public wxCommandEvent +{ +public: + FFSCheckRowsEvent(const int from, const int to) : + wxCommandEvent(FFS_CHECK_ROWS_EVENT), + rowFrom(from), + rowTo(to) {} + + virtual wxEvent* Clone() const + { + return new FFSCheckRowsEvent(rowFrom, rowTo); + } + + const int rowFrom; + const int rowTo; +}; + +typedef void (wxEvtHandler::*FFSCheckRowsEventFunction)(FFSCheckRowsEvent&); + +#define FFSCheckRowsEventHandler(func) \ + (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(FFSCheckRowsEventFunction, &func) + +//-------------------------------------------------------------------------------------------- +//SELECTING SYNC DIRECTION + +extern const wxEventType FFS_SYNC_DIRECTION_EVENT; //define new event type + +class FFSSyncDirectionEvent : public wxCommandEvent +{ +public: + FFSSyncDirectionEvent(const int from, const int to, const FreeFileSync::SyncDirection dir) : + wxCommandEvent(FFS_SYNC_DIRECTION_EVENT), + rowFrom(from), + rowTo(to), + direction(dir) {} + + virtual wxEvent* Clone() const + { + return new FFSSyncDirectionEvent(rowFrom, rowTo, direction); + } + + const int rowFrom; + const int rowTo; + const FreeFileSync::SyncDirection direction; +}; + +typedef void (wxEvtHandler::*FFSSyncDirectionEventFunction)(FFSSyncDirectionEvent&); + +#define FFSSyncDirectionEventHandler(func) \ + (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(FFSSyncDirectionEventFunction, &func) + + #endif // CUSTOMGRID_H_INCLUDED diff --git a/library/customButton.cpp b/library/customButton.cpp index 02cfdad0..fc686d3f 100644 --- a/library/customButton.cpp +++ b/library/customButton.cpp @@ -126,6 +126,9 @@ void linearInterpolation(wxImage& img) wxBitmap wxButtonWithImage::createBitmapFromText(const wxString& text) { + if (text.empty()) + return wxBitmap(); + wxFont currentFont = wxBitmapButton::GetFont(); wxColor textColor = wxBitmapButton::GetForegroundColour(); diff --git a/library/fileHandling.cpp b/library/fileHandling.cpp index 4f8caec6..b6d3d9d7 100644 --- a/library/fileHandling.cpp +++ b/library/fileHandling.cpp @@ -284,18 +284,25 @@ private: }; +class KernelDllHandler //dynamically load windows API functions +{ + typedef DWORD WINAPI (*GetFinalPath)( + HANDLE hFile, + LPTSTR lpszFilePath, + DWORD cchFilePath, + DWORD dwFlags); -typedef DWORD WINAPI (*GetFinalPath)( - HANDLE hFile, - LPTSTR lpszFilePath, - DWORD cchFilePath, - DWORD dwFlags); +public: + static const KernelDllHandler& getInstance() //lazy creation of KernelDllHandler + { + static KernelDllHandler instance; + return instance; + } + GetFinalPath getFinalPathNameByHandle; -class DllHandler //dynamically load windows API functions -{ -public: - DllHandler() : +private: + KernelDllHandler() : getFinalPathNameByHandle(NULL), hKernel(NULL) { @@ -305,26 +312,15 @@ public: getFinalPathNameByHandle = reinterpret_cast<GetFinalPath>(::GetProcAddress(hKernel, "GetFinalPathNameByHandleW")); //load unicode version! } - ~DllHandler() + ~KernelDllHandler() { if (hKernel) ::FreeLibrary(hKernel); } - GetFinalPath getFinalPathNameByHandle; - -private: HINSTANCE hKernel; }; -inline -DllHandler& getDllHandler() //lazy creation of DllHandler -{ - static DllHandler instance; - return instance; -} - - Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target path of symbolic link to a directory { //open handle to target of symbolic link @@ -340,13 +336,13 @@ Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target pa CloseHandleOnExit dummy(hDir); - if (getDllHandler().getFinalPathNameByHandle == NULL ) + if (KernelDllHandler::getInstance().getFinalPathNameByHandle == NULL ) throw FileError(Zstring(_("Error loading library function:")) + wxT("\n\"") + wxT("GetFinalPathNameByHandleW") + wxT("\"")); const unsigned BUFFER_SIZE = 10000; TCHAR targetPath[BUFFER_SIZE]; - const DWORD rv = getDllHandler().getFinalPathNameByHandle( + const DWORD rv = KernelDllHandler::getInstance().getFinalPathNameByHandle( hDir, targetPath, BUFFER_SIZE, @@ -669,8 +665,8 @@ inline void setWin32FileInformation(const FILETIME& lastWriteTime, const DWORD fileSizeHigh, const DWORD fileSizeLow, FreeFileSync::FileInfo& output) { //convert UTC FILETIME to ANSI C format (number of seconds since Jan. 1st 1970 UTC) - wxLongLong writeTimeLong(lastWriteTime.dwHighDateTime, lastWriteTime.dwLowDateTime); - writeTimeLong /= 10000000; //reduce precision to 1 second (FILETIME has unit 10^-7 s) + wxLongLong writeTimeLong(wxInt32(lastWriteTime.dwHighDateTime), lastWriteTime.dwLowDateTime); + writeTimeLong /= 10000000; //reduce precision to 1 second (FILETIME has unit 10^-7 s) writeTimeLong -= wxLongLong(2, 3054539008UL); //timeshift between ansi C time and FILETIME in seconds == 11644473600s output.lastWriteTimeRaw = writeTimeLong; diff --git a/library/filter.cpp b/library/filter.cpp index d5255367..d9ba8c5f 100644 --- a/library/filter.cpp +++ b/library/filter.cpp @@ -5,6 +5,8 @@ #include <vector> #include "resources.h" +using FreeFileSync::FilterProcess; + void compoundStringToTable(const Zstring& compoundInput, const DefaultChar* delimiter, std::vector<Zstring>& output) { @@ -42,21 +44,6 @@ void mergeVectors(std::vector<Zstring>& changing, const std::vector<Zstring>& in } -inline -void formatFilterString(Zstring& filter) -{ -#ifdef FFS_WIN - //Windows does NOT distinguish between upper/lower-case - filter.MakeLower(); -#elif defined FFS_LINUX - //Linux DOES distinguish between upper/lower-case -//nothing to do here -#else - adapt; -#endif -} - - std::vector<Zstring> compoundStringToFilter(const Zstring& filterString) { //delimiters may be ';' or '\n' @@ -78,12 +65,26 @@ std::vector<Zstring> compoundStringToFilter(const Zstring& filterString) inline void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, std::set<Zstring>& directoryFilter) { - //Test if filtername ends with GlobalResources::FILE_NAME_SEPARATOR, ignoring '*' and '?'. - //If so, treat as filter for directory and add to directoryFilter. - if (!filtername.empty()) + Zstring filterFormatted = filtername; + +#ifdef FFS_WIN + //Windows does NOT distinguish between upper/lower-case + filterFormatted.MakeLower(); +#elif defined FFS_LINUX + //Linux DOES distinguish between upper/lower-case +//nothing to do here +#endif + + //remove leading separators (keep BEFORE test for Zstring::empty()!) + if (filterFormatted.length() > 0 && *filterFormatted.c_str() == GlobalResources::FILE_NAME_SEPARATOR) + filterFormatted = Zstring(filterFormatted.c_str() + 1); + + if (!filterFormatted.empty()) { - const DefaultChar* filter = filtername.c_str(); - int i = filtername.length() - 1; + //Test if filterFormatted ends with GlobalResources::FILE_NAME_SEPARATOR, ignoring '*' and '?'. + //If so, treat as filter for directory and add to directoryFilter. + const DefaultChar* filter = filterFormatted.c_str(); + int i = filterFormatted.length() - 1; while (filter[i] == DefaultChar('*') || filter[i] == DefaultChar('?')) { --i; @@ -94,37 +95,46 @@ void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, st if (i >= 0 && filter[i] == GlobalResources::FILE_NAME_SEPARATOR) //last FILE_NAME_SEPARATOR found { - if (i != int(filtername.length()) - 1) // "name\*" + if (i != int(filterFormatted.length()) - 1) // "name\*" { - fileFilter.insert(filtername); - directoryFilter.insert(filtername); + fileFilter.insert(filterFormatted); + directoryFilter.insert(filterFormatted); } - //else: "name\" -> not inserted directly + //else // "name\" if (i > 0) // "name\*" or "name\": add "name" to directory filter - directoryFilter.insert(Zstring(filtername.c_str(), i)); + directoryFilter.insert(Zstring(filterFormatted.c_str(), i)); } else { - fileFilter.insert(filtername); - directoryFilter.insert(filtername); + fileFilter.insert(filterFormatted); + directoryFilter.insert(filterFormatted); } } } inline -bool matchesFilter(const Zstring& name, const std::set<Zstring>& filter) +bool matchesFilter(const DefaultChar* name, const std::set<Zstring>& filter) { +#ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case + Zstring nameFormatted = name; + nameFormatted.MakeLower(); +#elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case + const DefaultChar* const nameFormatted = name; //nothing to do here +#endif + for (std::set<Zstring>::iterator j = filter.begin(); j != filter.end(); ++j) - if (name.Matches(*j)) + if (Zstring::Matches(nameFormatted, *j)) return true; return false; } +//############################################################## + -void FreeFileSync::filterGridData(FolderComparison& folderCmp, const wxString& includeFilter, const wxString& excludeFilter) +FilterProcess::FilterProcess(const wxString& includeFilter, const wxString& excludeFilter) { //no need for regular expressions! In tests wxRegex was by factor of 10 slower than wxString::Matches()!! @@ -133,26 +143,37 @@ void FreeFileSync::filterGridData(FolderComparison& folderCmp, const wxString& i std::vector<Zstring> includeList = compoundStringToFilter(includeFilter.c_str()); std::vector<Zstring> excludeList = compoundStringToFilter(excludeFilter.c_str()); -//############################################################## //setup include/exclude filters for files and directories - std::set<Zstring> filterFileIn; - std::set<Zstring> filterFolderIn; for (std::vector<Zstring>::iterator i = includeList.begin(); i != includeList.end(); ++i) - { - formatFilterString(*i); //format entry addFilterEntry(*i, filterFileIn, filterFolderIn); - } - std::set<Zstring> filterFileEx; - std::set<Zstring> filterFolderEx; for (std::vector<Zstring>::iterator i = excludeList.begin(); i != excludeList.end(); ++i) - { - formatFilterString(*i); //format entry addFilterEntry(*i, filterFileEx, filterFolderEx); - } +} + + +bool FilterProcess::matchesFileFilter(const DefaultChar* relFilename) const +{ + if ( matchesFilter(relFilename, filterFileIn) && //process include filters + !matchesFilter(relFilename, filterFileEx)) //process exclude filters + return true; + else + return false; +} + + +bool FilterProcess::matchesDirFilter(const DefaultChar* relDirname) const +{ + if ( matchesFilter(relDirname, filterFolderIn) && //process include filters + !matchesFilter(relDirname, filterFolderEx)) //process exclude filters + return true; + else + return false; +} -//############################################################## +void FilterProcess::filterGridData(FolderComparison& folderCmp) const +{ //execute filtering... for (FolderComparison::iterator j = folderCmp.begin(); j != folderCmp.end(); ++j) { @@ -160,18 +181,10 @@ void FreeFileSync::filterGridData(FolderComparison& folderCmp, const wxString& i for (FileComparison::iterator i = fileCmp.begin(); i != fileCmp.end(); ++i) { - Zstring filenameLeft = i->fileDescrLeft.fullName; - Zstring filenameRight = i->fileDescrRight.fullName; - - formatFilterString(filenameLeft); - formatFilterString(filenameRight); - - //left hand side if (i->fileDescrLeft.objType == FileDescrLine::TYPE_FILE) { - if ( !matchesFilter(filenameLeft, filterFileIn) || //process include filters - matchesFilter(filenameLeft, filterFileEx)) //process exclude filters + if (!matchesFileFilter(i->fileDescrLeft.relativeName.c_str())) { i->selectedForSynchronization = false; continue; @@ -179,19 +192,16 @@ void FreeFileSync::filterGridData(FolderComparison& folderCmp, const wxString& i } else if (i->fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY) { - if ( !matchesFilter(filenameLeft, filterFolderIn) || //process include filters - matchesFilter(filenameLeft, filterFolderEx)) //process exclude filters + if (!matchesDirFilter(i->fileDescrLeft.relativeName.c_str())) { i->selectedForSynchronization = false; continue; } } - //right hand side - if (i->fileDescrRight.objType == FileDescrLine::TYPE_FILE) + else if (i->fileDescrRight.objType == FileDescrLine::TYPE_FILE) { - if ( !matchesFilter(filenameRight, filterFileIn) || //process include filters - matchesFilter(filenameRight, filterFileEx)) //process exclude filters + if (!matchesFileFilter(i->fileDescrRight.relativeName.c_str())) { i->selectedForSynchronization = false; continue; @@ -199,8 +209,7 @@ void FreeFileSync::filterGridData(FolderComparison& folderCmp, const wxString& i } else if (i->fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY) { - if ( !matchesFilter(filenameRight, filterFolderIn) || //process include filters - matchesFilter(filenameRight, filterFolderEx)) //process exclude filters + if (!matchesDirFilter(i->fileDescrRight.relativeName.c_str())) { i->selectedForSynchronization = false; continue; @@ -227,14 +236,14 @@ void inOrExcludeAllRows(FreeFileSync::FolderComparison& folderCmp) } -void FreeFileSync::includeAllRowsOnGrid(FolderComparison& folderCmp) +void FilterProcess::includeAllRowsOnGrid(FolderComparison& folderCmp) { //remove all filters on currentGridData inOrExcludeAllRows<true>(folderCmp); } -void FreeFileSync::excludeAllRowsOnGrid(FolderComparison& folderCmp) +void FilterProcess::excludeAllRowsOnGrid(FolderComparison& folderCmp) { //exclude all rows on currentGridData inOrExcludeAllRows<false>(folderCmp); diff --git a/library/filter.h b/library/filter.h index 3d0598e1..dd716680 100644 --- a/library/filter.h +++ b/library/filter.h @@ -6,9 +6,25 @@ namespace FreeFileSync { - void filterGridData(FolderComparison& folderCmp, const wxString& includeFilter, const wxString& excludeFilter); - void includeAllRowsOnGrid(FolderComparison& folderCmp); - void excludeAllRowsOnGrid(FolderComparison& folderCmp); + class FilterProcess //relative filtering + { + public: + FilterProcess(const wxString& includeFilter, const wxString& excludeFilter); + + bool matchesFileFilter(const DefaultChar* relFilename) const; + bool matchesDirFilter(const DefaultChar* relDirname) const; + + void filterGridData(FolderComparison& folderCmp) const; + + static void includeAllRowsOnGrid(FolderComparison& folderCmp); + static void excludeAllRowsOnGrid(FolderComparison& folderCmp); + + private: + std::set<Zstring> filterFileIn; + std::set<Zstring> filterFolderIn; + std::set<Zstring> filterFileEx; + std::set<Zstring> filterFolderEx; + }; } diff --git a/library/localization.cpp b/library/localization.cpp index 328f37be..ef433012 100644 --- a/library/localization.cpp +++ b/library/localization.cpp @@ -129,7 +129,7 @@ void CustomLocale::setLanguage(const int language) currentLanguage = wxLANGUAGE_ENGLISH; } - static bool initialized = false; //wxLocale is a global too! + static bool initialized = false; //wxLocale is a static global too! if (!initialized) { initialized = true; @@ -152,7 +152,7 @@ void CustomLocale::setLanguage(const int language) //Linux: 0xa \n //Mac: 0xd \r //Win: 0xd 0xa \r\n <- language files are in Windows format - for (int rowNumber = 0; langFile.getline(temp, bufferSize, 0xd); ++rowNumber) //specify delimiter explicitly + for (int rowNumber = 0; langFile.getline(temp, bufferSize, 0xD); ++rowNumber) //specify delimiter explicitly { langFile.get(); //discard the 0xa character @@ -165,8 +165,11 @@ void CustomLocale::setLanguage(const int language) currentLine.original = formattedString; else { - currentLine.translation = formattedString; - translationDB->insert(currentLine); + if (!formattedString.empty()) + { + currentLine.translation = formattedString; + translationDB->insert(currentLine); + } } } langFile.close(); diff --git a/library/processXml.cpp b/library/processXml.cpp index c16b9d76..750bd879 100644 --- a/library/processXml.cpp +++ b/library/processXml.cpp @@ -19,12 +19,12 @@ const wxString xmlAccess::GLOBAL_CONFIG_FILE = wxT("GlobalSettings.xml"); 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(SyncDirection& output, const TiXmlElement* parent, const std::string& name); bool readXmlElementValue(bool& output, const TiXmlElement* parent, const std::string& name); 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 SyncDirection value); void addXmlElement(TiXmlElement* parent, const std::string& name, const bool value); @@ -306,17 +306,17 @@ bool readXmlElementValue(CompareVariant& output, const TiXmlElement* parent, con } -bool readXmlElementValue(SyncConfiguration::Direction& output, const TiXmlElement* parent, const std::string& name) +bool readXmlElementValue(SyncDirection& output, const TiXmlElement* parent, const std::string& name) { std::string dummy; if (readXmlElementValue(dummy, parent, name)) { if (dummy == "left") - output = SyncConfiguration::SYNC_DIR_LEFT; + output = SYNC_DIR_LEFT; else if (dummy == "right") - output = SyncConfiguration::SYNC_DIR_RIGHT; + output = SYNC_DIR_RIGHT; else //treat all other input as "none" - output = SyncConfiguration::SYNC_DIR_NONE; + output = SYNC_DIR_NONE; return true; } @@ -460,8 +460,8 @@ bool XmlConfigInput::readXmlGuiConfig(xmlAccess::XmlGuiConfig& outputCfg) if (guiConfig) { readXmlElementValue(outputCfg.hideFilteredElements, guiConfig, "HideFiltered"); - readXmlElementValue(outputCfg.ignoreErrors, guiConfig, "IgnoreErrors"); + readXmlElementValue(outputCfg.syncPreviewEnabled, guiConfig, "SyncPreviewActive"); } return true; @@ -508,7 +508,7 @@ bool XmlConfigInput::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputC TiXmlElement* global = hRoot.FirstChild("Shared").ToElement(); if (global) { - //program language + //try to read program language setting readXmlElementValue(outputCfg.shared.programLanguage, global, "Language"); //max. allowed file time deviation @@ -516,6 +516,9 @@ bool XmlConfigInput::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputC if (readXmlElementValue(dummy, global, "FileTimeTolerance")) outputCfg.shared.fileTimeTolerance = dummy; + //ignore +/- 1 hour due to DST change + readXmlElementValue(outputCfg.shared.ignoreOneHourDiff, global, "IgnoreOneHourDifference"); + //traverse into symbolic links (to folders) readXmlElementValue(outputCfg.shared.traverseDirectorySymlinks, global, "TraverseDirectorySymlinks"); @@ -537,6 +540,12 @@ bool XmlConfigInput::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputC //check free disk space readXmlElementValue(outputCfg.shared.warningNotEnoughDiskSpace, warnings, "CheckForFreeDiskSpace"); + + //check for unresolved conflicts + readXmlElementValue(outputCfg.shared.warningUnresolvedConflicts, warnings, "CheckForUnresolvedConflicts"); + + //small reminder that synchronization will be starting immediately + readXmlElementValue(outputCfg.shared.warningSynchronizationStarting, warnings, "SynchronizationStarting"); } //gui specific global settings (optional) @@ -558,19 +567,19 @@ bool XmlConfigInput::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputC //########################################################### //read column attributes TiXmlElement* leftColumn = TiXmlHandle(mainWindow).FirstChild("LeftColumns").FirstChild("Column").ToElement(); - unsigned int colType = 0; + unsigned int colPos = 0; while (leftColumn) { - const char* visible = leftColumn->Attribute("Visible"); - const char* position = leftColumn->Attribute("Position"); - const char* width = leftColumn->Attribute("Width"); + const char* type = leftColumn->Attribute("Type"); + const char* visible = leftColumn->Attribute("Visible"); + const char* width = leftColumn->Attribute("Width"); - if (visible && position && width) //may be NULL!! + if (type && visible && width) //may be NULL!! { xmlAccess::ColumnAttrib newAttrib; - newAttrib.type = xmlAccess::ColumnTypes(colType); + newAttrib.type = xmlAccess::ColumnTypes(globalFunctions::stringToInt(type)); newAttrib.visible = std::string(visible) != std::string("false"); - newAttrib.position = globalFunctions::stringToInt(position); + newAttrib.position = colPos; newAttrib.width = globalFunctions::stringToInt(width); outputCfg.gui.columnAttribLeft.push_back(newAttrib); } @@ -578,23 +587,23 @@ bool XmlConfigInput::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputC break; leftColumn = leftColumn->NextSiblingElement(); - ++colType; + ++colPos; } TiXmlElement* rightColumn = TiXmlHandle(mainWindow).FirstChild("RightColumns").FirstChild("Column").ToElement(); - colType = 0; + colPos = 0; while (rightColumn) { - const char* visible = rightColumn->Attribute("Visible"); - const char* position = rightColumn->Attribute("Position"); - const char* width = rightColumn->Attribute("Width"); + const char* type = rightColumn->Attribute("Type"); + const char* visible = rightColumn->Attribute("Visible"); + const char* width = rightColumn->Attribute("Width"); - if (visible && position && width) //may be NULL!! + if (type && visible && width) //may be NULL!! { xmlAccess::ColumnAttrib newAttrib; - newAttrib.type = xmlAccess::ColumnTypes(colType); + newAttrib.type = xmlAccess::ColumnTypes(globalFunctions::stringToInt(type)); newAttrib.visible = std::string(visible) != std::string("false"); - newAttrib.position = globalFunctions::stringToInt(position); + newAttrib.position = colPos; newAttrib.width = globalFunctions::stringToInt(width); outputCfg.gui.columnAttribRight.push_back(newAttrib); } @@ -602,7 +611,7 @@ bool XmlConfigInput::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputC break; rightColumn = rightColumn->NextSiblingElement(); - ++colType; + ++colPos; } //load folder history elements @@ -722,13 +731,13 @@ void addXmlElement(TiXmlElement* parent, const std::string& name, const long val } -void addXmlElement(TiXmlElement* parent, const std::string& name, const SyncConfiguration::Direction value) +void addXmlElement(TiXmlElement* parent, const std::string& name, const SyncDirection value) { - if (value == SyncConfiguration::SYNC_DIR_LEFT) + if (value == SYNC_DIR_LEFT) addXmlElement(parent, name, std::string("left")); - else if (value == SyncConfiguration::SYNC_DIR_RIGHT) + else if (value == SYNC_DIR_RIGHT) addXmlElement(parent, name, std::string("right")); - else if (value == SyncConfiguration::SYNC_DIR_NONE) + else if (value == SYNC_DIR_NONE) addXmlElement(parent, name, std::string("none")); else assert(false); @@ -841,8 +850,8 @@ bool XmlConfigOutput::writeXmlGuiConfig(const xmlAccess::XmlGuiConfig& inputCfg) root->LinkEndChild(guiConfig); addXmlElement(guiConfig, "HideFiltered", inputCfg.hideFilteredElements); - addXmlElement(guiConfig, "IgnoreErrors", inputCfg.ignoreErrors); + addXmlElement(guiConfig, "SyncPreviewActive", inputCfg.syncPreviewEnabled); return true; } @@ -885,6 +894,9 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& //max. allowed file time deviation addXmlElement(global, "FileTimeTolerance", int(inputCfg.shared.fileTimeTolerance)); + //ignore +/- 1 hour due to DST change + addXmlElement(global, "IgnoreOneHourDifference", inputCfg.shared.ignoreOneHourDiff); + //traverse into symbolic links (to folders) addXmlElement(global, "TraverseDirectorySymlinks", inputCfg.shared.traverseDirectorySymlinks); @@ -907,6 +919,12 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& //check free disk space addXmlElement(warnings, "CheckForFreeDiskSpace", inputCfg.shared.warningNotEnoughDiskSpace); + //check for unresolved conflicts + addXmlElement(warnings, "CheckForUnresolvedConflicts", inputCfg.shared.warningUnresolvedConflicts); + + //small reminder that synchronization will be starting immediately + addXmlElement(warnings, "SynchronizationStarting", inputCfg.shared.warningSynchronizationStarting); + //################################################################### //write global gui settings @@ -937,32 +955,32 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& TiXmlElement* leftColumn = new TiXmlElement("LeftColumns"); mainWindow->LinkEndChild(leftColumn); xmlAccess::ColumnAttributes columnAtrribLeftCopy = inputCfg.gui.columnAttribLeft; //can't change const vector - sort(columnAtrribLeftCopy.begin(), columnAtrribLeftCopy.end(), xmlAccess::sortByType); + sort(columnAtrribLeftCopy.begin(), columnAtrribLeftCopy.end(), xmlAccess::sortByPositionOnly); for (unsigned int i = 0; i < columnAtrribLeftCopy.size(); ++i) { TiXmlElement* subElement = new TiXmlElement("Column"); leftColumn->LinkEndChild(subElement); const xmlAccess::ColumnAttrib& colAttrib = columnAtrribLeftCopy[i]; + subElement->SetAttribute("Type", colAttrib.type); 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); xmlAccess::ColumnAttributes columnAtrribRightCopy = inputCfg.gui.columnAttribRight; - sort(columnAtrribRightCopy.begin(), columnAtrribRightCopy.end(), xmlAccess::sortByType); + sort(columnAtrribRightCopy.begin(), columnAtrribRightCopy.end(), xmlAccess::sortByPositionOnly); for (unsigned int i = 0; i < columnAtrribRightCopy.size(); ++i) { TiXmlElement* subElement = new TiXmlElement("Column"); rightColumn->LinkEndChild(subElement); const xmlAccess::ColumnAttrib& colAttrib = columnAtrribRightCopy[i]; + subElement->SetAttribute("Type", colAttrib.type); if (colAttrib.visible) subElement->SetAttribute("Visible", "true"); else subElement->SetAttribute("Visible", "false"); - subElement->SetAttribute("Position", colAttrib.position); subElement->SetAttribute("Width", colAttrib.width); } @@ -1094,7 +1112,9 @@ bool xmlAccess::supportForSymbolicLinks() void xmlAccess::XmlGlobalSettings::_Shared::resetWarnings() { - warningDependentFolders = true; - warningSignificantDifference = true; - warningNotEnoughDiskSpace = true; + warningDependentFolders = true; + warningSignificantDifference = true; + warningNotEnoughDiskSpace = true; + warningUnresolvedConflicts = true; + warningSynchronizationStarting = true; } diff --git a/library/processXml.h b/library/processXml.h index 763edbca..313fbfae 100644 --- a/library/processXml.h +++ b/library/processXml.h @@ -26,21 +26,21 @@ namespace xmlAccess enum ColumnTypes { - FILENAME = 0, + DIRECTORY, + FULL_PATH, REL_PATH, + FILENAME, SIZE, - DATE, - FULL_NAME, - DIRECTORY + DATE }; const unsigned COLUMN_TYPE_COUNT = 6; struct ColumnAttrib { ColumnTypes type; - bool visible; - unsigned position; - int width; + bool visible; + unsigned int position; + int width; }; typedef std::vector<ColumnAttrib> ColumnAttributes; @@ -51,20 +51,23 @@ namespace xmlAccess { XmlGuiConfig() : hideFilteredElements(false), - ignoreErrors(false) {} //initialize values + ignoreErrors(false), + syncPreviewEnabled(true) {} //initialize values FreeFileSync::MainConfiguration mainCfg; std::vector<FreeFileSync::FolderPair> directoryPairs; bool hideFilteredElements; bool ignoreErrors; //reaction on error situation during synchronization + bool syncPreviewEnabled; bool operator==(const XmlGuiConfig& other) const { - return mainCfg == other.mainCfg && - directoryPairs == other.directoryPairs && + return mainCfg == other.mainCfg && + directoryPairs == other.directoryPairs && hideFilteredElements == other.hideFilteredElements && - ignoreErrors == other.ignoreErrors; + ignoreErrors == other.ignoreErrors && + syncPreviewEnabled == other.syncPreviewEnabled; } bool operator!=(const XmlGuiConfig& other) const @@ -98,6 +101,7 @@ namespace xmlAccess _Shared() : programLanguage(retrieveSystemLanguage()), fileTimeTolerance(2), //default 2s: FAT vs NTFS + ignoreOneHourDiff(true), traverseDirectorySymlinks(false), copyFileSymlinks(supportForSymbolicLinks()), lastUpdateCheck(0) @@ -106,7 +110,8 @@ namespace xmlAccess } int programLanguage; - unsigned fileTimeTolerance; //max. allowed file time deviation + unsigned int fileTimeTolerance; //max. allowed file time deviation + bool ignoreOneHourDiff; //ignore +/- 1 hour due to DST change bool traverseDirectorySymlinks; bool copyFileSymlinks; //copy symbolic link instead of target file long lastUpdateCheck; //time of last update check @@ -117,6 +122,8 @@ namespace xmlAccess bool warningDependentFolders; bool warningSignificantDifference; bool warningNotEnoughDiskSpace; + bool warningUnresolvedConflicts; + bool warningSynchronizationStarting; } shared; //--------------------------------------------------------------------- diff --git a/library/resources.cpp b/library/resources.cpp index 23d1ac37..9e43a78a 100644 --- a/library/resources.cpp +++ b/library/resources.cpp @@ -37,29 +37,32 @@ GlobalResources::GlobalResources() bitmapResource[wxT("about_small.png")] = (bitmapAboutSmall = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("website.png")] = (bitmapWebsite = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("exit.png")] = (bitmapExit = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("sync.png")] = (bitmapSync = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("compare.png")] = (bitmapCompare = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("compare disabled.png")] = (bitmapCompareDisabled = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("sync.png")] = (bitmapSync = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("sync disabled.png")] = (bitmapSyncDisabled = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("swap.png")] = (bitmapSwap = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("help.png")] = (bitmapHelp = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("equal.png")] = (bitmapEqual = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("equalAct.png")] = (bitmapEqualAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("equalDeact.png")] = (bitmapEqualDeact = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("leftOnly.png")] = (bitmapLeftOnly = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("leftOnlyAct.png")] = (bitmapLeftOnlyAct = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("leftOnlyDeact.png")] = (bitmapLeftOnlyDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("rightOnly.png")] = (bitmapRightOnly = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("rightOnlyAct.png")] = (bitmapRightOnlyAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("rightOnlyDeact.png")] = (bitmapRightOnlyDeact = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("leftNewer.png")] = (bitmapLeftNewer = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("leftNewerAct.png")] = (bitmapLeftNewerAct = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("leftNewerDeact.png")] = (bitmapLeftNewerDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("different.png")] = (bitmapDifferent = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("differentAct.png")] = (bitmapDifferentAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("differentDeact.png")] = (bitmapDifferentDeact = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("rightNewer.png")] = (bitmapRightNewer = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("rightNewerAct.png")] = (bitmapRightNewerAct = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("rightNewerDeact.png")] = (bitmapRightNewerDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("rightOnly.png")] = (bitmapRightOnly = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("rightOnlyAct.png")] = (bitmapRightOnlyAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("rightOnlyDeact.png")] = (bitmapRightOnlyDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("different.png")] = (bitmapDifferent = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("differentAct.png")] = (bitmapDifferentAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("differentDeact.png")] = (bitmapDifferentDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("equal.png")] = (bitmapEqual = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("equalAct.png")] = (bitmapEqualAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("equalDeact.png")] = (bitmapEqualDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("conflictAct.png")] = (bitmapConflictAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("conflictDeact.png")] = (bitmapConflictDeact = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("include.png")] = (bitmapInclude = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("exclude.png")] = (bitmapExclude = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("filter active.png")] = (bitmapFilterOn = new wxBitmap(wxNullBitmap)); @@ -80,7 +83,7 @@ GlobalResources::GlobalResources() bitmapResource[wxT("statusSuccess.png")] = (bitmapStatusSuccess = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("statusWarning.png")] = (bitmapStatusWarning = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("statusScanning.png")] = (bitmapStatusScanning = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("statusComparing.png")] = (bitmapStatusComparing = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("statusBinaryCompare.png")]= (bitmapStatusBinCompare = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("statusSyncing.png")] = (bitmapStatusSyncing = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("logo.png")] = (bitmapLogo = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("statusEdge.png")] = (bitmapStatusEdge = new wxBitmap(wxNullBitmap)); @@ -104,6 +107,9 @@ GlobalResources::GlobalResources() bitmapResource[wxT("settings_small.png")] = (bitmapSettingsSmall = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("recycler.png")] = (bitmapRecycler = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("shift.png")] = (bitmapShift = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncConfig.png")] = (bitmapSyncCfg = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncPreview.png")] = (bitmapPreview = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncPreviewDisabl.png")] = (bitmapPreviewDisabled = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("question.png")] = (bitmapQuestion = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("china.png")] = (bitmapChina = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("holland.png")] = (bitmapHolland = new wxBitmap(wxNullBitmap)); @@ -118,6 +124,30 @@ GlobalResources::GlobalResources() bitmapResource[wxT("brazil.png")] = (bitmapBrazil = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("slovakia.png")] = (bitmapSlovakia = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("spain.png")] = (bitmapSpain = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirLeftAct.png")] = (bitmapSyncDirLeftAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirLeftDeact.png")] = (bitmapSyncDirLeftDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirRightAct.png")] = (bitmapSyncDirRightAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirRightDeact.png")] = (bitmapSyncDirRightDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirNoneAct.png")] = (bitmapSyncDirNoneAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirNoneDeact.png")] = (bitmapSyncDirNoneDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirLeftSmall.png")] = (bitmapSyncDirLeftSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirRightSmall.png")] = (bitmapSyncDirRightSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirNoneSmall.png")] = (bitmapSyncDirNoneSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("leftOnlySmall.png")] = (bitmapLeftOnlySmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("rightOnlySmall.png")] = (bitmapRightOnlySmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("leftNewerSmall.png")] = (bitmapLeftNewerSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("rightNewerSmall.png")] = (bitmapRightNewerSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("equalSmall.png")] = (bitmapEqualSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("differentSmall.png")] = (bitmapDifferentSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("conflictSmall.png")] = (bitmapConflictSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("create.png")] = (bitmapCreate = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("update.png")] = (bitmapUpdate = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("delete.png")] = (bitmapDelete = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("data.png")] = (bitmapData = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("cmpView.png")] = (bitmapCmpView = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncView.png")] = (bitmapSyncView = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("toggleViewSmall.png")] = (bitmapSwitchViewSmall = new wxBitmap(wxNullBitmap)); + //init all the other resource files animationMoney = new wxAnimation(wxNullAnimation); diff --git a/library/resources.h b/library/resources.h index 5de79ec2..60b4ab48 100644 --- a/library/resources.h +++ b/library/resources.h @@ -36,29 +36,32 @@ public: wxBitmap* bitmapAboutSmall; wxBitmap* bitmapWebsite; wxBitmap* bitmapExit; - wxBitmap* bitmapSync; wxBitmap* bitmapCompare; + wxBitmap* bitmapCompareDisabled; + wxBitmap* bitmapSync; wxBitmap* bitmapSyncDisabled; wxBitmap* bitmapSwap; wxBitmap* bitmapHelp; - wxBitmap* bitmapEqual; - wxBitmap* bitmapEqualAct; - wxBitmap* bitmapEqualDeact; wxBitmap* bitmapLeftOnly; wxBitmap* bitmapLeftOnlyAct; wxBitmap* bitmapLeftOnlyDeact; + wxBitmap* bitmapRightOnly; + wxBitmap* bitmapRightOnlyAct; + wxBitmap* bitmapRightOnlyDeact; wxBitmap* bitmapLeftNewer; wxBitmap* bitmapLeftNewerAct; wxBitmap* bitmapLeftNewerDeact; - wxBitmap* bitmapDifferent; - wxBitmap* bitmapDifferentAct; - wxBitmap* bitmapDifferentDeact; wxBitmap* bitmapRightNewer; wxBitmap* bitmapRightNewerAct; wxBitmap* bitmapRightNewerDeact; - wxBitmap* bitmapRightOnly; - wxBitmap* bitmapRightOnlyAct; - wxBitmap* bitmapRightOnlyDeact; + wxBitmap* bitmapEqual; + wxBitmap* bitmapEqualAct; + wxBitmap* bitmapEqualDeact; + wxBitmap* bitmapDifferent; + wxBitmap* bitmapDifferentAct; + wxBitmap* bitmapDifferentDeact; + wxBitmap* bitmapConflictAct; + wxBitmap* bitmapConflictDeact; wxBitmap* bitmapInclude; wxBitmap* bitmapExclude; wxBitmap* bitmapFilterOn; @@ -79,7 +82,7 @@ public: wxBitmap* bitmapStatusSuccess; wxBitmap* bitmapStatusWarning; wxBitmap* bitmapStatusScanning; - wxBitmap* bitmapStatusComparing; + wxBitmap* bitmapStatusBinCompare; wxBitmap* bitmapStatusSyncing; wxBitmap* bitmapLogo; wxBitmap* bitmapStatusEdge; @@ -103,6 +106,9 @@ public: wxBitmap* bitmapSettingsSmall; wxBitmap* bitmapRecycler; wxBitmap* bitmapShift; + wxBitmap* bitmapSyncCfg; + wxBitmap* bitmapPreview; + wxBitmap* bitmapPreviewDisabled; wxBitmap* bitmapQuestion; wxBitmap* bitmapChina; wxBitmap* bitmapHolland; @@ -117,6 +123,29 @@ public: wxBitmap* bitmapBrazil; wxBitmap* bitmapSlovakia; wxBitmap* bitmapSpain; + wxBitmap* bitmapSyncDirLeftAct; + wxBitmap* bitmapSyncDirLeftDeact; + wxBitmap* bitmapSyncDirRightAct; + wxBitmap* bitmapSyncDirRightDeact; + wxBitmap* bitmapSyncDirNoneAct; + wxBitmap* bitmapSyncDirNoneDeact; + wxBitmap* bitmapSyncDirLeftSmall; + wxBitmap* bitmapSyncDirRightSmall; + wxBitmap* bitmapSyncDirNoneSmall; + wxBitmap* bitmapLeftOnlySmall; + wxBitmap* bitmapRightOnlySmall; + wxBitmap* bitmapLeftNewerSmall; + wxBitmap* bitmapRightNewerSmall; + wxBitmap* bitmapEqualSmall; + wxBitmap* bitmapDifferentSmall; + wxBitmap* bitmapConflictSmall; + wxBitmap* bitmapCreate; + wxBitmap* bitmapUpdate; + wxBitmap* bitmapDelete; + wxBitmap* bitmapData; + wxBitmap* bitmapCmpView; + wxBitmap* bitmapSyncView; + wxBitmap* bitmapSwitchViewSmall; wxAnimation* animationMoney; wxAnimation* animationSync; diff --git a/library/statusHandler.cpp b/library/statusHandler.cpp index e19c9904..78dba057 100644 --- a/library/statusHandler.cpp +++ b/library/statusHandler.cpp @@ -16,8 +16,7 @@ void updateUiNow() bool updateUiIsAllowed() { static wxLongLong lastExec = 0; - - wxLongLong newExec = wxGetLocalTimeMillis(); + const wxLongLong newExec = wxGetLocalTimeMillis(); if (newExec - lastExec >= UI_UPDATE_INTERVAL) //perform ui updates not more often than necessary { diff --git a/library/statusHandler.h b/library/statusHandler.h index 18d9f129..fe64f3cd 100644 --- a/library/statusHandler.h +++ b/library/statusHandler.h @@ -54,7 +54,7 @@ public: virtual void forceUiRefresh() = 0; void requestUiRefresh(bool allowAbort = true); //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh() - void requestAbortion(); //does NOT call abortThisProcess immediately, but when appropriate (e.g. async. processes finished) + void requestAbortion(); //this does NOT call abortThisProcess immediately, but when appropriate (e.g. async. processes finished) bool abortIsRequested(); @@ -63,7 +63,7 @@ public: virtual void reportFatalError(const Zstring& errorMessage) = 0; //non-recoverable error situation, implement abort! virtual void reportWarning(const Zstring& warningMessage, bool& dontShowAgain) = 0; -protected: +private: virtual void abortThisProcess() = 0; bool abortRequested; diff --git a/library/zstring.cpp b/library/zstring.cpp index abded9d0..ddf1fc73 100644 --- a/library/zstring.cpp +++ b/library/zstring.cpp @@ -1,5 +1,4 @@ #include "zstring.h" -#include <wx/intl.h> #include "globalFunctions.h" #ifdef FFS_WIN @@ -124,6 +123,12 @@ bool Zstring::Matches(const DefaultChar* mask) const } +bool Zstring::Matches(const DefaultChar* name, const DefaultChar* mask) +{ + return matchesHelper(name, mask); +} + + Zstring& Zstring::Trim(bool fromRight) { const size_t thisLen = length(); diff --git a/library/zstring.h b/library/zstring.h index 2b6bc475..007922d8 100644 --- a/library/zstring.h +++ b/library/zstring.h @@ -66,6 +66,7 @@ public: Zstring BeforeLast(DefaultChar ch) const; size_t Find(DefaultChar ch, bool fromEnd) const; bool Matches(const DefaultChar* mask) const; + static bool Matches(const DefaultChar* name, const DefaultChar* mask); Zstring& Trim(bool fromRight); //from right or left Zstring& MakeLower(); |