summaryrefslogtreecommitdiff
path: root/library/CustomGrid.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'library/CustomGrid.cpp')
-rw-r--r--library/CustomGrid.cpp949
1 files changed, 564 insertions, 385 deletions
diff --git a/library/CustomGrid.cpp b/library/CustomGrid.cpp
index 048bc5e0..591230e2 100644
--- a/library/CustomGrid.cpp
+++ b/library/CustomGrid.cpp
@@ -6,16 +6,19 @@
#include "resources.h"
#include <typeinfo>
#include "../ui/gridView.h"
+#include "../synchronization.h"
#ifdef FFS_WIN
+#include <wx/timer.h>
#include <wx/icon.h>
-#include <wx/msw/wrapwin.h> //includes "windows.h"
+#include "iconBuffer.h"
+#include "statusHandler.h"
+#include <cmath>
#elif defined FFS_LINUX
#include <gtk/gtk.h>
#endif
-
using namespace FreeFileSync;
@@ -234,6 +237,7 @@ public:
return xmlAccess::ColumnTypes(1000);
}
+ virtual Zstring getFileName(const unsigned int row) const = 0;
private:
std::vector<xmlAccess::ColumnTypes> columnPositions;
@@ -271,11 +275,11 @@ public:
switch (getTypeAtPos(col))
{
case xmlAccess::FULL_PATH:
- return wxString(gridLine->fileDescrLeft.fullName.c_str()).BeforeLast(GlobalResources::FILE_NAME_SEPARATOR);
+ return wxString(gridLine->fileDescrLeft.fullName.c_str()).BeforeLast(FreeFileSync::FILE_NAME_SEPARATOR);
case xmlAccess::FILENAME: //filename
- return wxString(gridLine->fileDescrLeft.relativeName.c_str()).AfterLast(GlobalResources::FILE_NAME_SEPARATOR);
+ return wxString(gridLine->fileDescrLeft.relativeName.c_str()).AfterLast(FreeFileSync::FILE_NAME_SEPARATOR);
case xmlAccess::REL_PATH: //relative path
- return wxString(gridLine->fileDescrLeft.relativeName.c_str()).BeforeLast(GlobalResources::FILE_NAME_SEPARATOR);
+ return wxString(gridLine->fileDescrLeft.relativeName.c_str()).BeforeLast(FreeFileSync::FILE_NAME_SEPARATOR);
case xmlAccess::DIRECTORY:
return gridDataView->getFolderPair(row).leftDirectory.c_str();
case xmlAccess::SIZE: //file size
@@ -289,6 +293,17 @@ public:
return wxEmptyString;
}
+
+ virtual Zstring getFileName(const unsigned int row) const
+ {
+ const FileCompareLine* gridLine = getRawData(row);
+ if (gridLine)
+ return Zstring(gridLine->fileDescrLeft.fullName);
+ else
+ return Zstring();
+ }
+
+
private:
virtual const wxColour& getRowColor(int row) //rows that are filtered out are shown in different color
{
@@ -340,11 +355,11 @@ public:
switch (getTypeAtPos(col))
{
case xmlAccess::FULL_PATH:
- return wxString(gridLine->fileDescrRight.fullName.c_str()).BeforeLast(GlobalResources::FILE_NAME_SEPARATOR);
+ return wxString(gridLine->fileDescrRight.fullName.c_str()).BeforeLast(FreeFileSync::FILE_NAME_SEPARATOR);
case xmlAccess::FILENAME: //filename
- return wxString(gridLine->fileDescrRight.relativeName.c_str()).AfterLast(GlobalResources::FILE_NAME_SEPARATOR);
+ return wxString(gridLine->fileDescrRight.relativeName.c_str()).AfterLast(FreeFileSync::FILE_NAME_SEPARATOR);
case xmlAccess::REL_PATH: //relative path
- return wxString(gridLine->fileDescrRight.relativeName.c_str()).BeforeLast(GlobalResources::FILE_NAME_SEPARATOR);
+ return wxString(gridLine->fileDescrRight.relativeName.c_str()).BeforeLast(FreeFileSync::FILE_NAME_SEPARATOR);
case xmlAccess::DIRECTORY:
return gridDataView->getFolderPair(row).rightDirectory.c_str();
case xmlAccess::SIZE: //file size
@@ -358,6 +373,17 @@ public:
return wxEmptyString;
}
+
+ virtual Zstring getFileName(const unsigned int row) const
+ {
+ const FileCompareLine* gridLine = getRawData(row);
+ if (gridLine)
+ return Zstring(gridLine->fileDescrRight.fullName);
+ else
+ return Zstring();
+ }
+
+
private:
virtual const wxColour& getRowColor(int row) //rows that are filtered out are shown in different color
{
@@ -476,27 +502,43 @@ CustomGrid::CustomGrid(wxWindow *parent,
m_gridMiddle(NULL),
m_gridRight(NULL),
isLeading(false),
- currentSortColumn(-1),
- sortMarker(NULL)
+ m_marker(-1, ASCENDING)
{
//set color of selections
wxColour darkBlue(40, 35, 140);
SetSelectionBackground(darkBlue);
SetSelectionForeground(*wxWHITE);
+}
- //enhance grid functionality; identify leading grid by keyboard input or scroll action
- Connect(wxEVT_KEY_DOWN, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SCROLLWIN_TOP, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SCROLLWIN_BOTTOM, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SCROLLWIN_LINEUP, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SCROLLWIN_LINEDOWN, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SCROLLWIN_PAGEUP, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SCROLLWIN_PAGEDOWN, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SCROLLWIN_THUMBTRACK, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SCROLLWIN_THUMBRELEASE, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_GRID_LABEL_LEFT_CLICK, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- GetGridWindow()->Connect(wxEVT_LEFT_DOWN, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
+void CustomGrid::initSettings(CustomGridLeft* gridLeft,
+ CustomGridMiddle* gridMiddle,
+ CustomGridRight* gridRight,
+ const GridView* gridDataView)
+{
+ assert(this == gridLeft || this == gridRight || this == gridMiddle);
+
+ //these grids will scroll together
+ m_gridLeft = gridLeft;
+ m_gridRight = gridRight;
+ m_gridMiddle = gridMiddle;
+
+ //set underlying grid data
+ setGridDataTable(gridDataView);
+
+ //enhance grid functionality; identify leading grid by keyboard input or scroll action
+ Connect(wxEVT_KEY_DOWN, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
+ Connect(wxEVT_SCROLLWIN_TOP, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
+ Connect(wxEVT_SCROLLWIN_BOTTOM, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
+ Connect(wxEVT_SCROLLWIN_LINEUP, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
+ Connect(wxEVT_SCROLLWIN_LINEDOWN, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
+ Connect(wxEVT_SCROLLWIN_PAGEUP, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
+ Connect(wxEVT_SCROLLWIN_PAGEDOWN, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
+ Connect(wxEVT_SCROLLWIN_THUMBTRACK, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
+ Connect(wxEVT_SCROLLWIN_THUMBRELEASE, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
+ Connect(wxEVT_GRID_LABEL_LEFT_CLICK, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
+ GetGridWindow()->Connect(wxEVT_LEFT_DOWN, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
+ GetGridWindow()->Connect(wxEVT_RIGHT_DOWN, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
GetGridWindow()->Connect(wxEVT_ENTER_WINDOW, wxEventHandler(CustomGrid::adjustGridHeights), NULL, this);
}
@@ -507,58 +549,22 @@ bool CustomGrid::isLeadGrid() const
}
-inline
-bool gridsShouldBeCleared(const wxEvent& event)
+void CustomGrid::RefreshCell(int row, int col)
{
- try
- {
- const wxMouseEvent& mouseEvent = dynamic_cast<const wxMouseEvent&> (event);
-
- if (mouseEvent.ControlDown() || mouseEvent.ShiftDown())
- return false;
-
- if (mouseEvent.ButtonDown(wxMOUSE_BTN_LEFT))
- return true;
+ wxRect rectScrolled(CellToRect(row, col));
- return false;
- }
- catch (std::bad_cast&) {}
-
- try
- {
- const wxKeyEvent& keyEvent = dynamic_cast<const wxKeyEvent&> (event);
+ CalcScrolledPosition(rectScrolled.x, rectScrolled.y, &rectScrolled.x, &rectScrolled.y);
- if (keyEvent.ControlDown() || keyEvent.ShiftDown())
- return false;
+ GetGridWindow()->RefreshRect(rectScrolled); //note: CellToRect() and YToRow work on m_gridWindow NOT on the whole grid!
+}
- switch (keyEvent.GetKeyCode())
- {
- case WXK_SPACE:
- case WXK_TAB:
- case WXK_RETURN:
- case WXK_ESCAPE:
- case WXK_NUMPAD_ENTER:
- case WXK_LEFT:
- case WXK_UP:
- case WXK_RIGHT:
- case WXK_DOWN:
- case WXK_PAGEUP:
- case WXK_PAGEDOWN:
- case WXK_NUMPAD_PAGEUP:
- case WXK_NUMPAD_PAGEDOWN:
- case WXK_HOME:
- case WXK_END:
- case WXK_NUMPAD_HOME:
- case WXK_NUMPAD_END:
- return true;
- default:
- return false;
- }
- }
- catch (std::bad_cast&) {}
+void CustomGrid::DoPrepareDC(wxDC& dc)
+{
+ wxScrollHelper::DoPrepareDC(dc);
- return false;
+ if (isLeadGrid()) //avoid back coupling
+ alignOtherGrids(m_gridLeft, m_gridMiddle, m_gridRight); //scroll other grids
}
@@ -681,29 +687,84 @@ void additionalGridCommands(wxEvent& event, wxGrid* grid)
}
+inline
+bool gridsShouldBeCleared(const wxEvent& event)
+{
+ try
+ {
+ const wxMouseEvent& mouseEvent = dynamic_cast<const wxMouseEvent&> (event);
+
+ if (mouseEvent.ControlDown() || mouseEvent.ShiftDown())
+ return false;
+
+ if (mouseEvent.ButtonDown(wxMOUSE_BTN_LEFT))
+ return true;
+
+ return false;
+ }
+ catch (std::bad_cast&) {}
+
+ try
+ {
+ const wxKeyEvent& keyEvent = dynamic_cast<const wxKeyEvent&> (event);
+
+ if (keyEvent.ControlDown() || keyEvent.ShiftDown())
+ return false;
+
+ switch (keyEvent.GetKeyCode())
+ {
+ case WXK_SPACE:
+ case WXK_TAB:
+ case WXK_RETURN:
+ case WXK_ESCAPE:
+ case WXK_NUMPAD_ENTER:
+ case WXK_LEFT:
+ case WXK_UP:
+ case WXK_RIGHT:
+ case WXK_DOWN:
+ case WXK_PAGEUP:
+ case WXK_PAGEDOWN:
+ case WXK_NUMPAD_PAGEUP:
+ case WXK_NUMPAD_PAGEDOWN:
+ case WXK_HOME:
+ case WXK_END:
+ case WXK_NUMPAD_HOME:
+ case WXK_NUMPAD_END:
+ return true;
+ }
+
+ return false;
+ }
+ catch (std::bad_cast&) {}
+
+ return false;
+}
+
+
void CustomGrid::onGridAccess(wxEvent& event)
{
if (!isLeading)
{
- isLeading = true;
-
//notify other grids of new user focus
- if (m_gridLeft != this)
- m_gridLeft->isLeading = false;
- if (m_gridMiddle != this)
- m_gridMiddle->isLeading = false;
- if (m_gridRight != this)
- m_gridRight->isLeading = false;
+ m_gridLeft->isLeading = m_gridLeft == this;
+ m_gridMiddle->isLeading = m_gridMiddle == this;
+ m_gridRight->isLeading = m_gridRight == this;
wxGrid::SetFocus();
}
+ //clear grids
if (gridsShouldBeCleared(event))
{
m_gridLeft->ClearSelection();
+ m_gridMiddle->ClearSelection();
m_gridRight->ClearSelection();
}
+ //update row labels NOW (needed when scrolling if buttons keep being pressed)
+ m_gridLeft->GetGridRowLabelWindow()->Update();
+ m_gridRight->GetGridRowLabelWindow()->Update();
+
//support for additional short-cuts
additionalGridCommands(event, this); //event.Skip is handled here!
}
@@ -712,48 +773,46 @@ void CustomGrid::onGridAccess(wxEvent& event)
//workaround: ensure that all grids are properly aligned: add some extra window space to grids that have no horizontal scrollbar
void CustomGrid::adjustGridHeights(wxEvent& event)
{
- if (m_gridLeft && m_gridRight && m_gridMiddle)
- {
- int y1 = 0;
- int y2 = 0;
- int y3 = 0;
- int dummy = 0;
+ //m_gridLeft, m_gridRight, m_gridMiddle not NULL because called after initSettings()
- m_gridLeft->GetViewStart(&dummy, &y1);
- m_gridRight->GetViewStart(&dummy, &y2);
- m_gridMiddle->GetViewStart(&dummy, &y3);
+ int y1 = 0;
+ int y2 = 0;
+ int y3 = 0;
+ int dummy = 0;
- if (y1 != y2 || y2 != y3)
- {
- int yMax = std::max(y1, std::max(y2, y3));
-
- if (m_gridLeft->isLeadGrid()) //do not handle case (y1 == yMax) here!!! Avoid back coupling!
- m_gridLeft->SetMargins(0, 0);
- else if (y1 < yMax)
- m_gridLeft->SetMargins(0, 30);
-
- if (m_gridRight->isLeadGrid())
- m_gridRight->SetMargins(0, 0);
- else if (y2 < yMax)
- m_gridRight->SetMargins(0, 30);
-
- if (m_gridMiddle->isLeadGrid())
- m_gridMiddle->SetMargins(0, 0);
- else if (y3 < yMax)
- m_gridMiddle->SetMargins(0, 30);
-
- m_gridLeft->ForceRefresh();
- m_gridRight->ForceRefresh();
- m_gridMiddle->ForceRefresh();
- }
+ m_gridLeft->GetViewStart(&dummy, &y1);
+ m_gridRight->GetViewStart(&dummy, &y2);
+ m_gridMiddle->GetViewStart(&dummy, &y3);
+
+ if (y1 != y2 || y2 != y3)
+ {
+ int yMax = std::max(y1, std::max(y2, y3));
+
+ if (m_gridLeft->isLeadGrid()) //do not handle case (y1 == yMax) here!!! Avoid back coupling!
+ m_gridLeft->SetMargins(0, 0);
+ else if (y1 < yMax)
+ m_gridLeft->SetMargins(0, 30);
+
+ if (m_gridRight->isLeadGrid())
+ m_gridRight->SetMargins(0, 0);
+ else if (y2 < yMax)
+ m_gridRight->SetMargins(0, 30);
+
+ if (m_gridMiddle->isLeadGrid())
+ m_gridMiddle->SetMargins(0, 0);
+ else if (y3 < yMax)
+ m_gridMiddle->SetMargins(0, 30);
+
+ m_gridLeft->ForceRefresh();
+ m_gridRight->ForceRefresh();
+ m_gridMiddle->ForceRefresh();
}
}
-void CustomGrid::setSortMarker(const int sortColumn, const wxBitmap* bitmap)
+void CustomGrid::setSortMarker(SortMarker marker)
{
- currentSortColumn = sortColumn;
- sortMarker = bitmap;
+ m_marker = marker;
}
@@ -761,8 +820,13 @@ 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
+ if (col == m_marker.first)
+ {
+ if (m_marker.second == ASCENDING)
+ dc.DrawBitmap(*GlobalResources::getInstance().bitmapSmallUp, GetColRight(col) - 16 - 2, 2, true); //respect 2-pixel border
+ else
+ dc.DrawBitmap(*GlobalResources::getInstance().bitmapSmallDown, GetColRight(col) - 16 - 2, 2, true); //respect 2-pixel border
+ }
}
@@ -821,118 +885,119 @@ std::set<int> CustomGrid::getAllSelectedRows() const
//############################################################################################
//CustomGrid specializations
-template <bool leftSide, bool showFileIcons>
+#ifdef FFS_WIN
+template <bool showFileIcons>
class GridCellRenderer : public wxGridCellStringRenderer
{
public:
- GridCellRenderer(CustomGridTableRim* gridDataTable) : m_gridDataTable(gridDataTable) {};
+ GridCellRenderer(CustomGridRim::LoadSuccess& loadIconSuccess, const CustomGridTableRim* gridDataTable) :
+ m_loadIconSuccess(loadIconSuccess),
+ m_gridDataTable(gridDataTable) {}
virtual void Draw(wxGrid& grid,
wxGridCellAttr& attr,
wxDC& dc,
- const wxRect& rect,
+ const wxRect& rect, //unscrolled rect
int row, int col,
bool isSelected)
{
-#ifdef FFS_WIN
//############## show windows explorer file icons ######################
if (showFileIcons) //evaluate at compile time
{
- const int ICON_SIZE = 16; //size in pixel
-
if ( m_gridDataTable->getTypeAtPos(col) == xmlAccess::FILENAME &&
- rect.GetWidth() >= ICON_SIZE)
+ rect.GetWidth() >= IconBuffer::ICON_SIZE)
{
//retrieve grid data
- const FileCompareLine* rowData = m_gridDataTable->getRawData(row);
- if (rowData) //valid row
+ const Zstring fileName = m_gridDataTable->getFileName(row);
+ if (!fileName.empty())
{
- const DefaultChar* filename;
- if (leftSide) //evaluate at compile time
- filename = rowData->fileDescrLeft.fullName.c_str();
- else
- filename = rowData->fileDescrRight.fullName.c_str();
-
- if (*filename != DefaultChar(0)) //test if filename is empty
+ // Partitioning:
+ // _____________________
+ // | 2 pix | icon | rest |
+ // ---------------------
+
+ //clear area where icon will be placed
+ wxRect rectShrinked(rect);
+ rectShrinked.SetWidth(IconBuffer::ICON_SIZE + 2); //add 2 pixel border
+ wxGridCellRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected);
+
+ //try to draw icon
+ wxIcon icon;
+ const bool iconLoaded = IconBuffer::getInstance().requestIcon(fileName, &icon); //returns false if icon is not in buffer
+ if (iconLoaded)
+ dc.DrawIcon(icon, rectShrinked.GetX() + 2, rectShrinked.GetY());
+
+ //-----------------------------------------------------------------------------------------------
+ //only mark as successful if icon was drawn fully!
+ //(attention: when scrolling, rows get partially updated, which can result in the upper half being blank!)
+
+ //rect where icon was placed
+ wxRect iconRect(rect); //unscrolled
+ iconRect.x += 2;
+ iconRect.SetWidth(IconBuffer::ICON_SIZE);
+
+ //convert to scrolled coordinates
+ grid.CalcScrolledPosition(iconRect.x, iconRect.y, &iconRect.x, &iconRect.y);
+
+ bool iconDrawnFully = false;
+ wxRegionIterator regionsInv(grid.GetGridWindow()->GetUpdateRegion());
+ while (regionsInv)
{
- // Get the file icon.
- SHFILEINFO fileInfo;
- fileInfo.hIcon = 0; //initialize hIcon
-
- if (SHGetFileInfo(filename, //NOTE: CoInitializeEx()/CoUninitialize() implicitly called by wxWidgets on program startup!
- 0,
- &fileInfo,
- sizeof(fileInfo),
- SHGFI_ICON | SHGFI_SMALLICON))
+ if (regionsInv.GetRect().Contains(iconRect))
{
- //clear area where icon will be placed
- wxRect rectShrinked(rect);
- rectShrinked.SetWidth(ICON_SIZE + 2); //add 2 pixel border
- wxGridCellRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected);
-
- //draw icon
- if (fileInfo.hIcon != 0) //fix for weird error: SHGetFileInfo() might return successfully WITHOUT filling fileInfo.hIcon!!
- { //bug report: https://sourceforge.net/tracker/?func=detail&aid=2768004&group_id=234430&atid=1093080
- wxIcon icon;
- icon.SetHICON(static_cast<WXHICON>(fileInfo.hIcon));
- icon.SetSize(ICON_SIZE, ICON_SIZE);
-
- dc.DrawIcon(icon, rectShrinked.GetX() + 2, rectShrinked.GetY());
-
- if (!DestroyIcon(fileInfo.hIcon))
- throw RuntimeException(wxString(wxT("Error deallocating Icon handle!\n\n")) + FreeFileSync::getLastErrorFormatted());
- }
-
- //draw rest
- rectShrinked.SetWidth(rect.GetWidth() - ICON_SIZE - 2);
- rectShrinked.SetX(rect.GetX() + ICON_SIZE + 2);
- wxGridCellStringRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected);
- return;
+ iconDrawnFully = true;
+ break;
}
+ ++regionsInv;
}
+ //-----------------------------------------------------------------------------------------------
+
+
+ //save status of last icon load -> used for async. icon loading
+ m_loadIconSuccess[row] = iconLoaded && iconDrawnFully;
+
+ //draw rest
+ wxRect rest(rect); //unscrolled
+ rest.x += IconBuffer::ICON_SIZE + 2;
+ rest.width -= IconBuffer::ICON_SIZE + 2;
+
+ wxGridCellStringRenderer::Draw(grid, attr, dc, rest, row, col, isSelected);
+ return;
}
}
}
//default
wxGridCellStringRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
-
-#elif defined FFS_LINUX
- wxGridCellStringRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
-#endif
}
private:
+ CustomGridRim::LoadSuccess& m_loadIconSuccess;
const CustomGridTableRim* const m_gridDataTable;
};
+#endif
//----------------------------------------------------------------------------------------
-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);
-}
+CustomGridRim::CustomGridRim(wxWindow *parent,
+ wxWindowID id,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style,
+ const wxString& name) :
+ CustomGrid(parent, id, pos, size, style, name)
+#ifdef FFS_WIN
+ , fileIconsAreEnabled(false)
+#endif
+{}
void CustomGridRim::updateGridSizes()
{
- assert(gridDataTable);
- gridDataTable->updateGridSizes();
+ assert(getGridDataTable());
+ getGridDataTable()->updateGridSizes();
}
@@ -1046,8 +1111,8 @@ void CustomGridRim::setColumnAttributes(const xmlAccess::ColumnAttributes& attr)
newPositions.push_back(columnSettings[i].type);
//set column positions
- assert(gridDataTable);
- gridDataTable->setupColumns(newPositions);
+ assert(getGridDataTable());
+ getGridDataTable()->setupColumns(newPositions);
//set column width (set them after setupColumns!)
for (unsigned int i = 0; i < newPositions.size(); ++i)
@@ -1071,8 +1136,8 @@ void CustomGridRim::setColumnAttributes(const xmlAccess::ColumnAttributes& attr)
xmlAccess::ColumnTypes CustomGridRim::getTypeAtPos(unsigned pos) const
{
- assert(gridDataTable);
- return gridDataTable->getTypeAtPos(pos);
+ assert(getGridDataTable());
+ return getGridDataTable()->getTypeAtPos(pos);
}
@@ -1097,6 +1162,132 @@ wxString CustomGridRim::getTypeName(xmlAccess::ColumnTypes colType)
return wxEmptyString; //dummy
}
+
+CustomGridTableRim* CustomGridRim::getGridDataTable()
+{ //let the non-const call the const version: see Meyers Effective C++
+ return const_cast<CustomGridTableRim*>(static_cast<const CustomGridRim*>(this)->getGridDataTable());
+}
+
+
+#ifdef FFS_WIN
+void CustomGridRim::enableFileIcons(const bool value)
+{
+ fileIconsAreEnabled = value;
+
+ if (value)
+ SetDefaultRenderer(new GridCellRenderer<true>(loadIconSuccess, getGridDataTable())); //SetDefaultRenderer takes ownership!
+ else
+ SetDefaultRenderer(new GridCellRenderer<false>(loadIconSuccess, getGridDataTable()));
+
+ Refresh();
+}
+
+
+CustomGridRim::VisibleRowRange CustomGridRim::getVisibleRows()
+{
+ int dummy = -1;
+ int height = -1;
+ GetGridWindow()->GetClientSize(&dummy, &height);
+
+ if (height >= 0)
+ {
+ int topRowY = -1;
+ CalcUnscrolledPosition(0, 0, &dummy, &topRowY);
+
+ if (topRowY >= 0)
+ {
+ const int topRow = YToRow(topRowY);
+ const int rowCount = static_cast<int>(ceil(height / static_cast<double>(GetDefaultRowSize()))); // = height / rowHeight rounded up
+ const int bottomRow = topRow + rowCount - 1;
+
+ return VisibleRowRange(topRow, bottomRow); //"top" means here top of the screen: => smaller value
+ }
+ }
+
+ return VisibleRowRange(0, 0);
+}
+
+
+void CustomGridRim::getIconsToBeLoaded(std::vector<Zstring>& newLoad) //loads all (not yet) drawn icons
+{
+ newLoad.clear();
+
+ if (fileIconsAreEnabled) //don't check too often! give worker thread some time to fetch data
+ {
+ const CustomGridTableRim* gridDataTable = getGridDataTable();
+ const VisibleRowRange rowsOnScreen = getVisibleRows();
+ const int totalCols = const_cast<CustomGridTableRim*>(gridDataTable)->GetNumberCols();
+ const int totalRows = const_cast<CustomGridTableRim*>(gridDataTable)->GetNumberRows();
+
+ //loop over all visible rows
+ const int firstRow = rowsOnScreen.first;
+ const int lastRow = std::min(int(rowsOnScreen.second), totalRows - 1);
+ const int rowNo = lastRow - firstRow + 1;
+
+ for (int i = 0; i < rowNo; ++i)
+ {
+ //alternate when adding rows: first, last, first + 1, last - 1 ...
+ const int currentRow = i % 2 == 0 ?
+ firstRow + i / 2 :
+ lastRow - (i - 1) / 2;
+
+ LoadSuccess::const_iterator j = loadIconSuccess.find(currentRow);
+ if (j != loadIconSuccess.end() && j->second == false) //find failed attempts to load icon
+ {
+ const Zstring fileName = gridDataTable->getFileName(currentRow);
+ if (!fileName.empty())
+ {
+ //test if they are already loaded in buffer:
+ if (FreeFileSync::IconBuffer::getInstance().requestIcon(fileName))
+ {
+ //exists in buffer: refresh Row
+ for (int k = 0; k < totalCols; ++k)
+ if (gridDataTable->getTypeAtPos(k) == xmlAccess::FILENAME)
+ {
+ RefreshCell(currentRow, k);
+ break;
+ }
+ }
+ else //not yet in buffer: mark for async. loading
+ {
+ newLoad.push_back(fileName);
+ }
+ }
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------------------------
+
+
+//update file icons periodically: use SINGLE instance to coordinate left and right grid at once
+IconUpdater::IconUpdater(CustomGridLeft* leftGrid, CustomGridRight* rightGrid) :
+ m_leftGrid(leftGrid),
+ m_rightGrid(rightGrid),
+ m_timer(new wxTimer) //connect timer event for async. icon loading
+{
+ m_timer->Connect(wxEVT_TIMER, wxEventHandler(IconUpdater::loadIconsAsynchronously), NULL, this);
+ m_timer->Start(50); //timer interval
+}
+
+
+void IconUpdater::loadIconsAsynchronously(wxEvent& event) //loads all (not yet) drawn icons
+{
+ std::vector<Zstring> iconsLeft;
+ m_leftGrid->getIconsToBeLoaded(iconsLeft);
+
+ std::vector<Zstring> newLoad;
+ m_rightGrid->getIconsToBeLoaded(newLoad);
+
+ globalFunctions::mergeVectors(iconsLeft, newLoad);
+
+ FreeFileSync::IconBuffer::getInstance().setWorkload(newLoad); //attention: newLoad is invalidated after this call!!!
+
+ //event.Skip();
+}
+#endif
+
//----------------------------------------------------------------------------------------
@@ -1106,7 +1297,8 @@ CustomGridLeft::CustomGridLeft(wxWindow *parent,
const wxSize& size,
long style,
const wxString& name) :
- CustomGridRim(parent, id, pos, size, style, name) {}
+ CustomGridRim(parent, id, pos, size, style, name),
+ gridDataTable(NULL) {}
bool CustomGridLeft::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode)
@@ -1120,29 +1312,28 @@ bool CustomGridLeft::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectio
}
-void CustomGridLeft::enableFileIcons(const bool value)
+void CustomGridLeft::setGridDataTable(const GridView* gridDataView)
{
- if (value)
- SetDefaultRenderer(new GridCellRenderer<true, true>(gridDataTable)); //SetDefaultRenderer takes ownership!
- else
- SetDefaultRenderer(new GridCellRenderer<true, false>(gridDataTable));
+ //set underlying grid data
+ assert(gridDataTable);
+ gridDataTable->setGridDataTable(gridDataView);
+}
- Refresh();
+
+const CustomGridTableRim* CustomGridLeft::getGridDataTable() const
+{
+ return gridDataTable;
}
//this method is called when grid view changes: useful for parallel updating of multiple grids
-void CustomGridLeft::DoPrepareDC(wxDC& dc)
+void CustomGridLeft::alignOtherGrids(CustomGrid* gridLeft, CustomGrid* gridMiddle, CustomGrid* gridRight)
{
- wxScrollHelper::DoPrepareDC(dc);
-
- int x, y = 0;
- if (isLeadGrid()) //avoid back coupling
- {
- GetViewStart(&x, &y);
- m_gridMiddle->Scroll(-1, y); //scroll in y-direction only
- m_gridRight->Scroll(x, y);
- }
+ int x = 0;
+ int y = 0;
+ GetViewStart(&x, &y);
+ gridMiddle->Scroll(-1, y); //scroll in y-direction only
+ gridRight->Scroll(x, y);
}
@@ -1153,7 +1344,8 @@ CustomGridRight::CustomGridRight(wxWindow *parent,
const wxSize& size,
long style,
const wxString& name) :
- CustomGridRim(parent, id, pos, size, style, name) {}
+ CustomGridRim(parent, id, pos, size, style, name),
+ gridDataTable(NULL) {}
bool CustomGridRight::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode)
@@ -1165,33 +1357,49 @@ bool CustomGridRight::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelecti
}
-void CustomGridRight::enableFileIcons(const bool value)
+void CustomGridRight::setGridDataTable(const GridView* gridDataView)
{
- if (value)
- SetDefaultRenderer(new GridCellRenderer<false, true>(gridDataTable)); //SetDefaultRenderer takes ownership!
- else
- SetDefaultRenderer(new GridCellRenderer<false, false>(gridDataTable));
+ //set underlying grid data
+ assert(gridDataTable);
+ gridDataTable->setGridDataTable(gridDataView);
+}
- Refresh();
+
+const CustomGridTableRim* CustomGridRight::getGridDataTable() const
+{
+ return gridDataTable;
}
//this method is called when grid view changes: useful for parallel updating of multiple grids
-void CustomGridRight::DoPrepareDC(wxDC& dc)
+void CustomGridRight::alignOtherGrids(CustomGrid* gridLeft, CustomGrid* gridMiddle, CustomGrid* gridRight)
{
- wxScrollHelper::DoPrepareDC(dc);
-
- int x, y = 0;
- if (isLeadGrid()) //avoid back coupling
- {
- GetViewStart(&x, &y);
- m_gridLeft->Scroll(x, y);
- m_gridMiddle->Scroll(-1, y);
- }
+ int x = 0;
+ int y = 0;
+ GetViewStart(&x, &y);
+ gridLeft->Scroll(x, y);
+ gridMiddle->Scroll(-1, y);
}
//----------------------------------------------------------------------------------------
+class GridCellRendererMiddle : public wxGridCellStringRenderer
+{
+public:
+ GridCellRendererMiddle(const CustomGridMiddle* middleGrid) : m_gridMiddle(middleGrid) {};
+
+ virtual void Draw(wxGrid& grid,
+ wxGridCellAttr& attr,
+ wxDC& dc,
+ const wxRect& rect,
+ int row, int col,
+ bool isSelected);
+
+private:
+ const CustomGridMiddle* const m_gridMiddle;
+};
+
+
//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();
@@ -1220,13 +1428,46 @@ CustomGridMiddle::CustomGridMiddle(wxWindow *parent,
{
//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);
}
+bool CustomGridMiddle::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode)
+{
+ gridDataTable = new CustomGridTableMiddle;
+ 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(this)); //SetDefaultRenderer takes ownership!
+
+ return true;
+}
+
+
+#ifdef FFS_WIN //get rid of scrollbars; Windows: overwrite virtual method
+void CustomGridMiddle::SetScrollbar(int orientation, int position, int thumbSize, int range, bool refresh)
+{
+ wxWindow::SetScrollbar(orientation, 0, 0, 0, refresh);
+}
+#endif
+
+
+void CustomGridMiddle::setGridDataTable(const GridView* gridDataView) //called once on startup
+{
+ //set underlying grid data
+ assert(gridDataTable);
+ gridDataTable->setGridDataTable(gridDataView);
+
+#ifdef FFS_LINUX //get rid of scrollbars; Linux: change policy for GtkScrolledWindow
+ GtkWidget* gridWidget = wxWindow::m_widget;
+ GtkScrolledWindow* scrolledWindow = GTK_SCROLLED_WINDOW(gridWidget);
+ gtk_scrolled_window_set_policy(scrolledWindow, GTK_POLICY_NEVER, GTK_POLICY_NEVER);
+#endif
+}
+
+
void CustomGridMiddle::OnMouseMovement(wxMouseEvent& event)
{
const int highlightedRowOld = highlightedRow;
@@ -1234,25 +1475,17 @@ void CustomGridMiddle::OnMouseMovement(wxMouseEvent& event)
if (selectionRowBegin == -1) //change highlightning only if currently not dragging mouse
{
highlightedRow = mousePosToRow(event.GetPosition(), &highlightedPos);
- if (highlightedRow >= 0) RefreshRow(highlightedRow);
+ if (highlightedRow >= 0)
+ RefreshCell(highlightedRow, 0);
if ( highlightedRowOld >= 0 &&
highlightedRow != highlightedRowOld)
- RefreshRow(highlightedRowOld);
+ RefreshCell(highlightedRowOld, 0);
}
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;
@@ -1357,36 +1590,6 @@ int CustomGridMiddle::mousePosToRow(const wxPoint pos, BlockPosition* block)
}
-void CustomGridMiddle::initSettings(CustomGrid* gridLeft,
- CustomGrid* gridRight,
- CustomGrid* gridMiddle,
- const FreeFileSync::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);
-
-#ifdef FFS_LINUX //get rid of scrollbars; Linux: change policy for GtkScrolledWindow
- GtkWidget* gridWidget = wxWindow::m_widget;
- GtkScrolledWindow* scrolledWindow = GTK_SCROLLED_WINDOW(gridWidget);
- gtk_scrolled_window_set_policy(scrolledWindow, GTK_POLICY_NEVER, GTK_POLICY_NEVER);
-#endif
-}
-
-
-#ifdef FFS_WIN //get rid of scrollbars; Windows: overwrite virtual method
-void CustomGridMiddle::SetScrollbar(int orientation, int position, int thumbSize, int range, bool refresh)
-{
- wxWindow::SetScrollbar(orientation, 0, 0, 0, refresh);
-}
-#endif
-
-
void CustomGridMiddle::enableSyncPreview(bool value)
{
assert(gridDataTable);
@@ -1427,152 +1630,128 @@ void CustomGridMiddle::updateGridSizes()
}
-class GridCellRendererMiddle : public wxGridCellStringRenderer
+void GridCellRendererMiddle::Draw(wxGrid& grid,
+ wxGridCellAttr& attr,
+ wxDC& dc,
+ const wxRect& rect,
+ int row, int col,
+ bool isSelected)
{
-public:
- GridCellRendererMiddle(const CustomGridMiddle* middleGrid) : m_gridMiddle(middleGrid) {};
-
-
- virtual void Draw(wxGrid& grid,
- wxGridCellAttr& attr,
- wxDC& dc,
- const wxRect& rect,
- int row, int col,
- bool isSelected)
+ //retrieve grid data
+ const FileCompareLine* const rowData = m_gridMiddle->gridDataTable->getRawData(row);
+ if (rowData != NULL) //if valid row...
{
- //retrieve grid data
- const FileCompareLine* const rowData = m_gridMiddle->gridDataTable->getRawData(row);
- if (rowData) //no valid row
+ if (rect.GetWidth() > CHECK_BOX_WIDTH)
{
- if (rect.GetWidth() > CHECK_BOX_WIDTH)
- {
- wxRect rectShrinked(rect);
+ wxRect rectShrinked(rect);
- //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);
+ //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);
- //print image into first block
- rectShrinked.SetX(rect.GetX() + 1);
- bool selected = rowData->selectedForSynchronization;
+ //print image into first block
+ rectShrinked.SetX(rect.GetX() + 1);
+ bool selected = rowData->selectedForSynchronization;
- //HIGHLIGHTNING:
- if ( row == m_gridMiddle->highlightedRow &&
- m_gridMiddle->highlightedPos == CustomGridMiddle::BLOCKPOS_CHECK_BOX)
- selected = !selected;
-
- 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);
-
- //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)
+ selected = !selected;
- //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)
+ if (selected)
+ dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapCheckBoxTrue, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
+ else
+ dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapCheckBoxFalse, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
+
+ //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 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);
+ case CustomGridMiddle::BLOCKPOS_CHECK_BOX:
break;
- case FILE_RIGHT_NEWER:
- dc.DrawLabel(wxEmptyString, *globalResource.bitmapRightNewerSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
+ case CustomGridMiddle::BLOCKPOS_LEFT:
+ dc.DrawLabel(wxEmptyString, getSyncOpImage(rowData->cmpResult, true, SYNC_DIR_LEFT), rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
break;
- case FILE_DIFFERENT:
- dc.DrawLabel(wxEmptyString, *globalResource.bitmapDifferentSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
+ case CustomGridMiddle::BLOCKPOS_MIDDLE:
+ dc.DrawLabel(wxEmptyString, getSyncOpImage(rowData->cmpResult, true, SYNC_DIR_NONE), 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);
+ case CustomGridMiddle::BLOCKPOS_RIGHT:
+ dc.DrawLabel(wxEmptyString, getSyncOpImage(rowData->cmpResult, true, SYNC_DIR_RIGHT), rectShrinked, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
break;
}
+ else //default
+ {
+ const wxBitmap& syncOpIcon = getSyncOpImage(rowData->cmpResult, rowData->selectedForSynchronization, rowData->direction);
+ dc.DrawLabel(wxEmptyString, syncOpIcon, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
+ }
+ }
+ else //comparison results view
+ {
+ switch (rowData->cmpResult)
+ {
+ case FILE_LEFT_SIDE_ONLY:
+ dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapLeftOnlySmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
+ break;
+ case FILE_RIGHT_SIDE_ONLY:
+ dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapRightOnlySmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
+ break;
+ case FILE_LEFT_NEWER:
+ dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapLeftNewerSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
+ break;
+ case FILE_RIGHT_NEWER:
+ dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapRightNewerSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
+ break;
+ case FILE_DIFFERENT:
+ dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapDifferentSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
+ break;
+ case FILE_EQUAL:
+ dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapEqualSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
+ break;
+ case FILE_CONFLICT:
+ dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapConflictSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
+ break;
}
-
- return;
}
- }
- //fallback
- wxGridCellStringRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
+ return;
+ }
}
-private:
- const CustomGridMiddle* const m_gridMiddle;
-};
+ //fallback
+ wxGridCellStringRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
+}
-bool CustomGridMiddle::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode)
+//this method is called when grid view changes: useful for parallel updating of multiple grids
+void CustomGridMiddle::alignOtherGrids(CustomGrid* gridLeft, CustomGrid* gridMiddle, CustomGrid* gridRight)
{
- gridDataTable = new CustomGridTableMiddle;
- 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(this)); //SetDefaultRenderer takes ownership!
-
- return true;
+ int x = 0;
+ int y = 0;
+ GetViewStart(&x, &y);
+ gridLeft->Scroll(-1, y);
+ gridRight->Scroll(-1, y);
}
-//this method is called when grid view changes: useful for parallel updating of multiple grids
-void CustomGridMiddle::DoPrepareDC(wxDC& dc)
+void CustomGridMiddle::DrawColLabel(wxDC& dc, int col)
{
- wxScrollHelper::DoPrepareDC(dc);
+ CustomGrid::DrawColLabel(dc, col);
- int x, y = 0;
- if (isLeadGrid()) //avoid back coupling
- {
- GetViewStart(&x, &y);
- m_gridLeft->Scroll(-1, y);
- m_gridRight->Scroll(-1, y);
- }
+ const wxRect rect(GetColLeft(col), 0, GetColWidth(col), GetColLabelSize());
+
+ if (gridDataTable->syncPreviewIsActive())
+ dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapSyncViewSmall, rect, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL);
+ else
+ dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapCmpViewSmall, rect, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL);
}
bgstack15