summaryrefslogtreecommitdiff
path: root/library/CustomGrid.cpp
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:08:06 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:08:06 +0200
commitfbe76102e941b9f1edaf236788e42678f05fdf9a (patch)
treef5f538316019fa89be8dc478103490c3a826f3ac /library/CustomGrid.cpp
parent3.8 (diff)
downloadFreeFileSync-fbe76102e941b9f1edaf236788e42678f05fdf9a.tar.gz
FreeFileSync-fbe76102e941b9f1edaf236788e42678f05fdf9a.tar.bz2
FreeFileSync-fbe76102e941b9f1edaf236788e42678f05fdf9a.zip
3.9
Diffstat (limited to 'library/CustomGrid.cpp')
-rw-r--r--library/CustomGrid.cpp2104
1 files changed, 0 insertions, 2104 deletions
diff --git a/library/CustomGrid.cpp b/library/CustomGrid.cpp
deleted file mode 100644
index a9846f74..00000000
--- a/library/CustomGrid.cpp
+++ /dev/null
@@ -1,2104 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2010 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-//
-#include "customGrid.h"
-#include "../shared/systemConstants.h"
-#include "resources.h"
-#include <wx/dc.h>
-#include "../shared/util.h"
-#include "../shared/stringConv.h"
-#include "resources.h"
-#include <typeinfo>
-#include "../ui/gridView.h"
-#include "../synchronization.h"
-#include "../shared/customTooltip.h"
-#include <wx/dcclient.h>
-#include "iconBuffer.h"
-#include <wx/icon.h>
-
-#ifdef FFS_WIN
-#include <wx/timer.h>
-#include "statusHandler.h"
-#include <cmath>
-
-#elif defined FFS_LINUX
-#include <gtk/gtk.h>
-#endif
-
-using namespace FreeFileSync;
-
-
-const size_t MIN_ROW_COUNT = 15;
-
-//class containing pure grid data: basically the same as wxGridStringTable, but adds cell formatting
-
-/*
-class hierarchy:
- CustomGridTable
- /|\
- ________________|________________
- | |
- CustomGridTableRim |
- /|\ |
- __________|__________ |
- | | |
-CustomGridTableLeft CustomGridTableRight CustomGridTableMiddle
-*/
-
-class CustomGridTable : public wxGridTableBase
-{
-public:
- CustomGridTable(int initialRows = 0, int initialCols = 0) : //note: initialRows/initialCols MUST match with GetNumberRows()/GetNumberCols() at initialization!!!
- wxGridTableBase(),
- gridDataView(NULL),
- lastNrRows(initialRows),
- lastNrCols(initialCols) {}
-
-
- virtual ~CustomGridTable() {}
-
-
- void setGridDataTable(const GridView* view)
- {
- this->gridDataView = view;
- }
-
-
-//###########################################################################
-//grid standard input output methods, redirected directly to gridData to improve performance
-
- virtual int GetNumberRows()
- {
- if (gridDataView)
- return static_cast<int>(std::max(gridDataView->rowsOnView(), MIN_ROW_COUNT));
- else
- return 0; //grid is initialized with zero number of rows
- }
-
-
- virtual bool IsEmptyCell(int row, int col)
- {
- return false; //avoid overlapping cells
-
- //return (GetValue(row, col) == wxEmptyString);
- }
-
-
- virtual void SetValue(int row, int col, const wxString& value)
- {
- assert (false); //should not be used, since values are retrieved directly from gridDataView
- }
-
- //update dimensions of grid: no need for InsertRows(), AppendRows(), DeleteRows() anymore!!!
- void updateGridSizes()
- {
- const int currentNrRows = GetNumberRows();
-
- if (lastNrRows < currentNrRows)
- {
- if (GetView())
- {
- wxGridTableMessage msg(this,
- wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
- currentNrRows - lastNrRows);
-
- GetView()->ProcessTableMessage( msg );
- }
- }
- else if (lastNrRows > currentNrRows)
- {
- if (GetView())
- {
- wxGridTableMessage msg(this,
- wxGRIDTABLE_NOTIFY_ROWS_DELETED,
- 0,
- lastNrRows - currentNrRows);
-
- GetView()->ProcessTableMessage( msg );
- }
- }
- lastNrRows = currentNrRows;
-
- const int currentNrCols = GetNumberCols();
-
- if (lastNrCols < currentNrCols)
- {
- if (GetView())
- {
- wxGridTableMessage msg(this,
- wxGRIDTABLE_NOTIFY_COLS_APPENDED,
- currentNrCols - lastNrCols);
-
- GetView()->ProcessTableMessage( msg );
- }
- }
- else if (lastNrCols > currentNrCols)
- {
- if (GetView())
- {
- wxGridTableMessage msg(this,
- wxGRIDTABLE_NOTIFY_COLS_DELETED,
- 0,
- lastNrCols - currentNrCols);
-
- GetView()->ProcessTableMessage( msg );
- }
- }
- lastNrCols = currentNrCols;
- }
-//###########################################################################
-
-
- virtual wxGridCellAttr* GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind)
- {
- const wxColour color = getRowColor(row);
-
- //add color to some rows
- wxGridCellAttr* result = wxGridTableBase::GetAttr(row, col, kind);
- if (result)
- {
- if (result->GetBackgroundColour() == color)
- {
- return result;
- }
- else //grid attribute might be referenced by other nodes, so clone it!
- {
- wxGridCellAttr* attr = result->Clone(); //attr has ref-count 1
- result->DecRef();
- result = attr;
- }
- }
- else
- result = new wxGridCellAttr; //created with ref-count 1
-
- result->SetBackgroundColour(color);
-
- return result;
- }
-
-
- const FileSystemObject* getRawData(size_t row) const
- {
- if (gridDataView)
- return gridDataView->getObject(row); //returns NULL if request is not valid or not data found
-
- return NULL;
- }
-
-protected:
- static const wxColour COLOR_BLUE;
- static const wxColour COLOR_GREY;
- static const wxColour COLOR_ORANGE;
- static const wxColour COLOR_CMP_RED;
- static const wxColour COLOR_CMP_BLUE;
- static const wxColour COLOR_CMP_GREEN;
- static const wxColour COLOR_SYNC_BLUE;
- static const wxColour COLOR_SYNC_GREEN;
- static 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;
-};
-
-//see http://www.latiumsoftware.com/en/articles/00015.php#12 for "safe" colors
-const wxColour CustomGridTable::COLOR_ORANGE( 238, 201, 0);
-const wxColour CustomGridTable::COLOR_BLUE( 80, 110, 255);
-const wxColour CustomGridTable::COLOR_GREY( 212, 208, 200);
-const wxColour CustomGridTable::COLOR_CMP_RED( 249, 163, 165);
-const wxColour CustomGridTable::COLOR_CMP_BLUE( 144, 232, 246);
-const wxColour CustomGridTable::COLOR_CMP_GREEN( 147, 253, 159);
-const wxColour CustomGridTable::COLOR_SYNC_BLUE( 201, 203, 247);
-const wxColour CustomGridTable::COLOR_SYNC_GREEN(197, 248, 190);
-const wxColour CustomGridTable::COLOR_YELLOW( 247, 252, 62);
-
-
-class CustomGridTableRim : public CustomGridTable
-{
-public:
- virtual ~CustomGridTableRim() {}
-
- virtual int GetNumberCols()
- {
- return static_cast<int>(columnPositions.size());
- }
-
- virtual wxString GetColLabelValue( int col )
- {
- return CustomGridRim::getTypeName(getTypeAtPos(col));
- }
-
-
- void setupColumns(const std::vector<xmlAccess::ColumnTypes>& positions)
- {
- columnPositions = positions;
- updateGridSizes(); //add or remove columns
- }
-
-
- xmlAccess::ColumnTypes getTypeAtPos(size_t pos) const
- {
- if (pos < columnPositions.size())
- return columnPositions[pos];
- else
- return xmlAccess::DIRECTORY;
- }
-
- //get filename in order to retrieve the icon from it
- virtual Zstring getIconFile(size_t row) const = 0; //return "folder" if row points to a folder
-
-protected:
- template <SelectedSide side>
- wxString GetValueSub(int row, int col)
- {
- const FileSystemObject* fsObj = getRawData(row);
- if (fsObj)
- {
- if (!fsObj->isEmpty<side>())
- {
- struct GetValue : public FSObjectVisitor
- {
- GetValue(xmlAccess::ColumnTypes colType) : colType_(colType) {}
- virtual void visit(const FileMapping& fileObj)
- {
- switch (colType_)
- {
- case xmlAccess::FULL_PATH:
- value = zToWx(fileObj.getFullName<side>().BeforeLast(globalFunctions::FILE_NAME_SEPARATOR));
- break;
- case xmlAccess::FILENAME: //filename
- value = zToWx(fileObj.getShortName<side>());
- break;
- case xmlAccess::REL_PATH: //relative path
- value = zToWx(fileObj.getParentRelativeName());
- break;
- case xmlAccess::DIRECTORY:
- value = zToWx(fileObj.getBaseDirPf<side>());
- break;
- case xmlAccess::SIZE: //file size
- value = FreeFileSync::numberToStringSep(fileObj.getFileSize<side>());
- break;
- case xmlAccess::DATE: //date
- value = FreeFileSync::utcTimeToLocalString(fileObj.getLastWriteTime<side>());
- break;
- case xmlAccess::EXTENSION: //file extension
- value = zToWx(fileObj.getExtension<side>());
- break;
- }
- }
-
- virtual void visit(const SymLinkMapping& linkObj)
- {
- switch (colType_)
- {
- case xmlAccess::FULL_PATH:
- value = zToWx(linkObj.getFullName<side>().BeforeLast(globalFunctions::FILE_NAME_SEPARATOR));
- break;
- case xmlAccess::FILENAME: //filename
- value = zToWx(linkObj.getShortName<side>());
- break;
- case xmlAccess::REL_PATH: //relative path
- value = zToWx(linkObj.getParentRelativeName());
- break;
- case xmlAccess::DIRECTORY:
- value = zToWx(linkObj.getBaseDirPf<side>());
- break;
- case xmlAccess::SIZE: //file size
- value = _("<Symlink>");
- break;
- case xmlAccess::DATE: //date
- value = FreeFileSync::utcTimeToLocalString(linkObj.getLastWriteTime<side>());
- break;
- case xmlAccess::EXTENSION: //file extension
- value = wxEmptyString;
- break;
- }
- }
-
- virtual void visit(const DirMapping& dirObj)
- {
- switch (colType_)
- {
- case xmlAccess::FULL_PATH:
- value = zToWx(dirObj.getFullName<side>());
- break;
- case xmlAccess::FILENAME:
- value = wxEmptyString;
- break;
- case xmlAccess::REL_PATH:
- value = zToWx(dirObj.getRelativeName<side>());
- break;
- case xmlAccess::DIRECTORY:
- value = zToWx(dirObj.getBaseDirPf<side>());
- break;
- case xmlAccess::SIZE: //file size
- value = _("<Directory>");
- break;
- case xmlAccess::DATE: //date
- value = wxEmptyString;
- break;
- case xmlAccess::EXTENSION: //file extension
- value = wxEmptyString;
- break;
- }
- }
- xmlAccess::ColumnTypes colType_;
- wxString value;
- } getVal(getTypeAtPos(col));
- fsObj->accept(getVal);
- return getVal.value;
- }
- }
- //if data is not found:
- return wxEmptyString;
- }
-
- template <SelectedSide side>
- Zstring getIconFileImpl(size_t row) const //return "folder" if row points to a folder
- {
- const FileSystemObject* fsObj = getRawData(row);
- if (fsObj && !fsObj->isEmpty<side>())
- {
- struct GetIcon : public FSObjectVisitor
- {
- virtual void visit(const FileMapping& fileObj)
- {
- //Optimization: if filename exists on both sides, always use left side's file:
- //Icon should be the same on both sides anyway...
- if (!fileObj.isEmpty<LEFT_SIDE>() && !fileObj.isEmpty<RIGHT_SIDE>())
- iconName = fileObj.getFullName<LEFT_SIDE>();
- else
- iconName = fileObj.getFullName<side>();
- }
- virtual void visit(const SymLinkMapping& linkObj)
- {
- iconName = linkObj.getLinkType<side>() == LinkDescriptor::TYPE_DIR ?
- DefaultStr("folder") :
- linkObj.getFullName<side>();
- }
- virtual void visit(const DirMapping& dirObj)
- {
- iconName = DefaultStr("folder");
- }
-
- Zstring iconName;
- } getIcon;
- fsObj->accept(getIcon);
- return getIcon.iconName;
- }
-
- return Zstring();
- }
-
-
-private:
- virtual const wxColour getRowColor(int row) //rows that are filtered out are shown in different color
- {
- const FileSystemObject* fsObj = getRawData(row);
- if (fsObj)
- {
- //mark filtered rows
- if (!fsObj->isActive())
- return COLOR_BLUE;
-
- //mark directories and symlinks
- struct GetRowColor : public FSObjectVisitor
- {
- virtual void visit(const FileMapping& fileObj)
- {
- rowColor = *wxWHITE;
- }
- virtual void visit(const SymLinkMapping& linkObj)
- {
- rowColor = COLOR_ORANGE;
- }
- virtual void visit(const DirMapping& dirObj)
- {
- rowColor = COLOR_GREY;
- }
-
- wxColour rowColor;
- } getCol;
- fsObj->accept(getCol);
- return getCol.rowColor;
- }
- return *wxWHITE;
- }
-
- std::vector<xmlAccess::ColumnTypes> columnPositions;
-};
-
-
-class CustomGridTableLeft : public CustomGridTableRim
-{
-public:
-
- virtual wxString GetValue(int row, int col)
- {
- return CustomGridTableRim::GetValueSub<LEFT_SIDE>(row, col);
- }
-
- virtual Zstring getIconFile(size_t row) const //return "folder" if row points to a folder
- {
- return getIconFileImpl<LEFT_SIDE>(row);
- }
-};
-
-
-class CustomGridTableRight : public CustomGridTableRim
-{
-public:
- virtual wxString GetValue(int row, int col)
- {
- return CustomGridTableRim::GetValueSub<RIGHT_SIDE>(row, col);
- }
-
- virtual Zstring getIconFile(size_t row) const //return "folder" if row points to a folder
- {
- return getIconFileImpl<RIGHT_SIDE>(row);
- }
-};
-
-
-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!
- syncPreviewActive(false) {}
-
- virtual int GetNumberCols()
- {
- return 1;
- }
-
- virtual wxString GetColLabelValue( int col )
- {
- return wxEmptyString;
- }
-
- virtual wxString GetValue(int row, int col) //method used for exporting .csv file only!
- {
- const FileSystemObject* fsObj = getRawData(row);
- if (fsObj)
- {
- if (syncPreviewActive) //synchronization preview
- return getSymbol(fsObj->getSyncOperation());
- else
- return getSymbol(fsObj->getCategory());
- }
- 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
- {
- const FileSystemObject* fsObj = getRawData(row);
- if (fsObj)
- {
- //mark filtered rows
- if (!fsObj->isActive())
- return COLOR_BLUE;
-
- if (syncPreviewActive) //synchronization preview
- {
- switch (fsObj->getSyncOperation()) //evaluate comparison result and sync direction
- {
- case SO_CREATE_NEW_LEFT:
- case SO_DELETE_LEFT:
- case SO_OVERWRITE_LEFT:
- return COLOR_SYNC_BLUE;
- case SO_CREATE_NEW_RIGHT:
- case SO_DELETE_RIGHT:
- case SO_OVERWRITE_RIGHT:
- return COLOR_SYNC_GREEN;
- case SO_UNRESOLVED_CONFLICT:
- return COLOR_YELLOW;
- case SO_DO_NOTHING:
- case SO_EQUAL:
- return *wxWHITE;
- }
- }
- else //comparison results view
- {
- switch (fsObj->getCategory())
- {
- case FILE_LEFT_SIDE_ONLY:
- case FILE_RIGHT_SIDE_ONLY:
- return COLOR_CMP_GREEN;
- case FILE_LEFT_NEWER:
- case FILE_RIGHT_NEWER:
- return COLOR_CMP_BLUE;
- case FILE_DIFFERENT:
- 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
-};
-
-//########################################################################################################
-
-
-CustomGrid::CustomGrid(wxWindow *parent,
- wxWindowID id,
- const wxPoint& pos,
- const wxSize& size,
- long style,
- const wxString& name) :
- wxGrid(parent, id, pos, size, style, name),
- m_gridLeft(NULL),
- m_gridMiddle(NULL),
- m_gridRight(NULL),
- isLeading(false),
- m_marker(-1, ASCENDING)
-{
- //set color of selections
- wxColour darkBlue(40, 35, 140);
- SetSelectionBackground(darkBlue);
- SetSelectionForeground(*wxWHITE);
-}
-
-
-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);
- Connect(wxEVT_SET_FOCUS, wxEventHandler(CustomGrid::onGridAccess), NULL, this); //used by grid text-search
- 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);
-
- //parallel grid scrolling: do NOT use DoPrepareDC() to align grids! GDI resource leak! Use regular paint event instead:
- GetGridWindow()->Connect(wxEVT_PAINT, wxEventHandler(CustomGrid::OnPaintGrid), NULL, this);
-}
-
-
-void CustomGrid::release() //release connection to FreeFileSync::GridView
-{
- setGridDataTable(NULL);
-}
-
-
-bool CustomGrid::isLeadGrid() const
-{
- return isLeading;
-}
-
-
-void CustomGrid::RefreshCell(int row, int col)
-{
- wxRect rectScrolled(CellToRect(row, col));
-
- CalcScrolledPosition(rectScrolled.x, rectScrolled.y, &rectScrolled.x, &rectScrolled.y);
-
- GetGridWindow()->RefreshRect(rectScrolled); //note: CellToRect() and YToRow work on m_gridWindow NOT on the whole grid!
-}
-
-
-void CustomGrid::OnPaintGrid(wxEvent& event)
-{
- if (isLeadGrid()) //avoid back coupling
- alignOtherGrids(m_gridLeft, m_gridMiddle, m_gridRight); //scroll other grids
- event.Skip();
-}
-
-
-void moveCursorWhileSelecting(const int anchor, const int oldPos, const int newPos, wxGrid* grid)
-{
- //note: all positions are valid in this context!
-
- grid->SetGridCursor( newPos, grid->GetGridCursorCol());
- grid->MakeCellVisible(newPos, grid->GetGridCursorCol());
-
- if (oldPos < newPos)
- {
- for (int i = oldPos; i < std::min(anchor, newPos); ++i)
- grid->DeselectRow(i); //remove selection
-
- for (int i = std::max(oldPos, anchor); i <= newPos; ++i)
- grid->SelectRow(i, true); //add to selection
- }
- else
- {
- for (int i = std::max(newPos, anchor) + 1; i <= oldPos; ++i)
- grid->DeselectRow(i); //remove selection
-
- for (int i = newPos; i <= std::min(oldPos, anchor); ++i)
- grid->SelectRow(i, true); //add to selection
- }
-}
-
-
-void execGridCommands(wxEvent& event, wxGrid* grid)
-{
- static int anchorRow = 0;
- if ( grid->GetNumberRows() == 0 ||
- grid->GetNumberCols() == 0)
- return;
-
- const wxKeyEvent* keyEvent = dynamic_cast<const wxKeyEvent*> (&event);
- if (keyEvent)
- {
- //ensure cursorOldPos is always a valid row!
- const int cursorOldPos = std::max(std::min(grid->GetGridCursorRow(), grid->GetNumberRows() - 1), 0);
- const int cursorOldColumn = std::max(std::min(grid->GetGridCursorCol(), grid->GetNumberCols() - 1), 0);
-
- const bool shiftPressed = keyEvent->ShiftDown();
- const bool altPressed = keyEvent->AltDown();
- const bool ctrlPressed = keyEvent->ControlDown();
- const bool noModPressed = !shiftPressed && !altPressed && !ctrlPressed;
- const int keyCode = keyEvent->GetKeyCode();
-
-
- //SHIFT + X
- if (shiftPressed && keyCode == WXK_UP)
- {
- const int cursorNewPos = std::max(cursorOldPos - 1, 0);
- moveCursorWhileSelecting(anchorRow, cursorOldPos, cursorNewPos, grid);
- return; //no event.Skip()
- }
- else if (shiftPressed && keyCode == WXK_DOWN)
- {
- const int cursorNewPos = std::min(cursorOldPos + 1, grid->GetNumberRows() - 1);
- moveCursorWhileSelecting(anchorRow, cursorOldPos, cursorNewPos, grid);
- return; //no event.Skip()
- }
- else if (shiftPressed && keyCode == WXK_LEFT)
- {
- const int cursorColumn = std::max(cursorOldColumn - 1, 0);
- grid->SetGridCursor(cursorOldPos, cursorColumn);
- grid->MakeCellVisible(cursorOldPos, cursorColumn);
- return; //no event.Skip()
- }
- else if (shiftPressed && keyCode == WXK_RIGHT)
- {
- const int cursorColumn = std::min(cursorOldColumn + 1, grid->GetNumberCols() - 1);
- grid->SetGridCursor(cursorOldPos, cursorColumn);
- grid->MakeCellVisible(cursorOldPos, cursorColumn);
- return; //no event.Skip()
- }
- else if (shiftPressed && (keyCode == WXK_PAGEUP || keyCode == WXK_NUMPAD_PAGEUP))
- {
- const int rowsPerPage = grid->GetGridWindow()->GetSize().GetHeight() / grid->GetDefaultRowSize();
- const int cursorNewPos = std::max(cursorOldPos - rowsPerPage, 0);
- moveCursorWhileSelecting(anchorRow, cursorOldPos, cursorNewPos, grid);
- return; //no event.Skip()
- }
- else if (shiftPressed && (keyCode == WXK_PAGEDOWN || keyCode == WXK_NUMPAD_PAGEDOWN))
- {
- const int rowsPerPage = grid->GetGridWindow()->GetSize().GetHeight() / grid->GetDefaultRowSize();
- const int cursorNewPos = std::min(cursorOldPos + rowsPerPage, grid->GetNumberRows() - 1);
- moveCursorWhileSelecting(anchorRow, cursorOldPos, cursorNewPos, grid);
- return; //no event.Skip()
- }
- else if (shiftPressed && (keyCode == WXK_HOME || keyCode == WXK_NUMPAD_HOME))
- {
- const int cursorNewPos = 0;
- moveCursorWhileSelecting(anchorRow, cursorOldPos, cursorNewPos, grid);
- return; //no event.Skip()
- }
- else if (shiftPressed && (keyCode == WXK_END || keyCode == WXK_NUMPAD_END))
- {
- const int cursorNewPos = grid->GetNumberRows() - 1;
- moveCursorWhileSelecting(anchorRow, cursorOldPos, cursorNewPos, grid);
- return; //no event.Skip()
- }
-
- //CTRL + X
- else if (ctrlPressed && keyCode == WXK_LEFT)
- {
- grid->SetGridCursor(grid->GetGridCursorRow(), 0);
- grid->MakeCellVisible(grid->GetGridCursorRow(), 0);
- return; //no event.Skip()
- }
- else if (ctrlPressed && keyCode == WXK_RIGHT)
- {
- grid->SetGridCursor(grid->GetGridCursorRow(), grid->GetNumberCols() - 1);
- grid->MakeCellVisible(grid->GetGridCursorRow(), grid->GetNumberCols() - 1);
- return; //no event.Skip()
- }
- else if ((ctrlPressed && keyCode == WXK_UP) ||
- ((noModPressed || ctrlPressed) && (keyCode == WXK_HOME || keyCode == WXK_NUMPAD_HOME)))
- {
- grid->SetGridCursor(0, grid->GetGridCursorCol());
- grid->MakeCellVisible(0, grid->GetGridCursorCol());
- return; //no event.Skip()
- }
- else if ((ctrlPressed && keyCode == WXK_DOWN) ||
- ((noModPressed || ctrlPressed) && (keyCode == WXK_END || keyCode == WXK_NUMPAD_END)))
- {
- grid->SetGridCursor(grid->GetNumberRows() - 1, grid->GetGridCursorCol());
- grid->MakeCellVisible(grid->GetNumberRows() - 1, grid->GetGridCursorCol());
- return; //no event.Skip()
- }
-
- //button without additonal control keys pressed
- else if (noModPressed && keyCode == WXK_UP)
- {
- const int cursorNewPos = std::max(cursorOldPos - 1, 0);
- grid->SetGridCursor(cursorNewPos, grid->GetGridCursorCol());
- grid->MakeCellVisible(cursorNewPos, grid->GetGridCursorCol());
- return; //no event.Skip()
- }
- else if (noModPressed && keyCode == WXK_DOWN)
- {
- const int cursorNewPos = std::min(cursorOldPos + 1, grid->GetNumberRows() - 1);
- grid->SetGridCursor(cursorNewPos, grid->GetGridCursorCol());
- grid->MakeCellVisible(cursorNewPos, grid->GetGridCursorCol());
- return; //no event.Skip()
- }
- else if (noModPressed && keyCode == WXK_LEFT)
- {
- const int cursorColumn = std::max(cursorOldColumn - 1, 0);
- grid->SetGridCursor(cursorOldPos, cursorColumn);
- grid->MakeCellVisible(cursorOldPos, cursorColumn);
- return; //no event.Skip()
- }
- else if (noModPressed && keyCode == WXK_RIGHT)
- {
- const int cursorColumn = std::min(cursorOldColumn + 1, grid->GetNumberCols() - 1);
- grid->SetGridCursor(cursorOldPos, cursorColumn);
- grid->MakeCellVisible(cursorOldPos, cursorColumn);
- return; //no event.Skip()
- }
- else if ((noModPressed || ctrlPressed) && (keyCode == WXK_PAGEUP || keyCode == WXK_NUMPAD_PAGEUP))
- {
- const int rowsPerPage = grid->GetGridWindow()->GetSize().GetHeight() / grid->GetDefaultRowSize();
- const int cursorNewPos = std::max(cursorOldPos - rowsPerPage, 0);
- grid->SetGridCursor(cursorNewPos, grid->GetGridCursorCol());
- grid->MakeCellVisible(cursorNewPos, grid->GetGridCursorCol());
- return; //no event.Skip()
- }
- else if ((noModPressed || ctrlPressed) && (keyCode == WXK_PAGEDOWN || keyCode == WXK_NUMPAD_PAGEDOWN))
- {
- const int rowsPerPage = grid->GetGridWindow()->GetSize().GetHeight() / grid->GetDefaultRowSize();
- const int cursorNewPos = std::min(cursorOldPos + rowsPerPage, grid->GetNumberRows() - 1);
- grid->SetGridCursor(cursorNewPos, grid->GetGridCursorCol());
- grid->MakeCellVisible(cursorNewPos, grid->GetGridCursorCol());
- return; //no event.Skip()
- }
- }
-
- anchorRow = grid->GetGridCursorRow();
- event.Skip(); //let event delegate!
-}
-
-
-inline
-bool gridsShouldBeCleared(const wxEvent& event)
-{
- const wxMouseEvent* mouseEvent = dynamic_cast<const wxMouseEvent*>(&event);
- if (mouseEvent)
- {
- if (mouseEvent->ControlDown() || mouseEvent->ShiftDown())
- return false;
-
- if (mouseEvent->ButtonDown(wxMOUSE_BTN_LEFT))
- return true;
-
- return false;
- }
- else
- {
- const wxKeyEvent* keyEvent = dynamic_cast<const wxKeyEvent*>(&event);
- if (keyEvent)
- {
- if (keyEvent->ControlDown() || keyEvent->AltDown() || keyEvent->ShiftDown())
- return false;
-
- switch (keyEvent->GetKeyCode())
- {
- 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;
- }
- }
-
- return false;
-}
-
-
-void CustomGrid::onGridAccess(wxEvent& event)
-{
- if (!isLeading)
- {
- //notify other grids of new user focus
- 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 custom short-cuts (overwriting wxWidgets functionality!)
- execGridCommands(event, this); //event.Skip is handled here!
-}
-
-
-//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)
-{
- //m_gridLeft, m_gridRight, m_gridMiddle not NULL because called after initSettings()
-
- int y1 = 0;
- int y2 = 0;
- int y3 = 0;
- int dummy = 0;
-
- 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(SortMarker marker)
-{
- m_marker = marker;
-}
-
-
-void CustomGrid::DrawColLabel(wxDC& dc, int col)
-{
- wxGrid::DrawColLabel(dc, col);
-
- if (col == m_marker.first)
- {
- if (m_marker.second == ASCENDING)
- dc.DrawBitmap(GlobalResources::getInstance().getImageByName(wxT("smallUp")), GetColRight(col) - 16 - 2, 2, true); //respect 2-pixel border
- else
- dc.DrawBitmap(GlobalResources::getInstance().getImageByName(wxT("smallDown")), GetColRight(col) - 16 - 2, 2, true); //respect 2-pixel border
- }
-}
-
-
-std::set<size_t> CustomGrid::getAllSelectedRows() const
-{
- std::set<size_t> output;
-
- const wxArrayInt selectedRows = this->GetSelectedRows();
- if (!selectedRows.IsEmpty())
- {
- for (size_t 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 (size_t k = 0; k < singlySelected.GetCount(); ++k)
- output.insert(singlySelected[k].GetRow());
- }
-
- const wxGridCellCoordsArray tmpArrayTop = this->GetSelectionBlockTopLeft();
- if (!tmpArrayTop.IsEmpty())
- {
- wxGridCellCoordsArray tmpArrayBottom = this->GetSelectionBlockBottomRight();
-
- size_t arrayCount = tmpArrayTop.GetCount();
-
- if (arrayCount == tmpArrayBottom.GetCount())
- {
- for (size_t 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
-
-template <bool showFileIcons>
-class GridCellRenderer : public wxGridCellStringRenderer
-{
-public:
- 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, //unscrolled rect
- int row, int col,
- bool isSelected)
- {
- //############## show windows explorer file icons ######################
-
- if ( showFileIcons && //evaluate at compile time
- m_gridDataTable->getTypeAtPos(col) == xmlAccess::FILENAME)
- {
- if (rect.GetWidth() >= IconBuffer::ICON_SIZE)
- {
- // Partitioning:
- // _____________________
- // | 2 pix | icon | rest |
- // ---------------------
-
- //clear area where icon will be placed
- wxRect rectShrinked(rect);
- rectShrinked.SetWidth(IconBuffer::ICON_SIZE + LEFT_BORDER); //add 2 pixel border
- wxGridCellRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected);
-
- //draw rest
- wxRect rest(rect); //unscrolled
- rest.x += IconBuffer::ICON_SIZE + LEFT_BORDER;
- rest.width -= IconBuffer::ICON_SIZE + LEFT_BORDER;
- wxGridCellStringRenderer::Draw(grid, attr, dc, rest, row, col, isSelected);
-
- //try to draw icon
- //retrieve grid data
- const Zstring fileName = m_gridDataTable->getIconFile(row);
- if (!fileName.empty())
- {
- //first check if it is a directory icon:
- if (fileName == DefaultStr("folder"))
- {
- dc.DrawIcon(IconBuffer::getDirectoryIcon(), rectShrinked.GetX() + LEFT_BORDER, rectShrinked.GetY());
- m_loadIconSuccess[row] = true; //save status of last icon load -> used for async. icon loading
- }
- else //retrieve file icon
- {
- wxIcon icon;
- bool iconDrawnFully = false;
- const bool iconLoaded = IconBuffer::getInstance().requestFileIcon(fileName, &icon); //returns false if icon is not in buffer
- if (iconLoaded)
- {
- dc.DrawIcon(icon, rectShrinked.GetX() + LEFT_BORDER, 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 += LEFT_BORDER;
- iconRect.SetWidth(IconBuffer::ICON_SIZE);
-
- //convert to scrolled coordinates
- grid.CalcScrolledPosition(iconRect.x, iconRect.y, &iconRect.x, &iconRect.y);
-
- wxRegionIterator regionsInv(grid.GetGridWindow()->GetUpdateRegion());
- while (regionsInv)
- {
- if (regionsInv.GetRect().Contains(iconRect))
- {
- iconDrawnFully = true;
- break;
- }
- ++regionsInv;
- }
- }
- //-----------------------------------------------------------------------------------------------
- //save status of last icon load -> used for async. icon loading
- m_loadIconSuccess[row] = iconLoaded && iconDrawnFully;
- }
- }
- return;
- }
- }
-
- //default
- wxGridCellStringRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
- }
-
-
- virtual wxSize GetBestSize(wxGrid& grid, //adapt reported width if file icons are shown
- wxGridCellAttr& attr,
- wxDC& dc,
- int row, int col)
- {
- if ( showFileIcons && //evaluate at compile time
- m_gridDataTable->getTypeAtPos(col) == xmlAccess::FILENAME)
- {
- wxSize rv = wxGridCellStringRenderer::GetBestSize(grid, attr, dc, row, col);
- rv.SetWidth(rv.GetWidth() + LEFT_BORDER + IconBuffer::ICON_SIZE);
- return rv;
- }
-
- //default
- return wxGridCellStringRenderer::GetBestSize(grid, attr, dc, row, col);
- }
-
-
-private:
- CustomGridRim::LoadSuccess& m_loadIconSuccess;
- const CustomGridTableRim* const m_gridDataTable;
-
- static const int LEFT_BORDER = 2;
-};
-
-//----------------------------------------------------------------------------------------
-
-CustomGridRim::CustomGridRim(wxWindow *parent,
- wxWindowID id,
- const wxPoint& pos,
- const wxSize& size,
- long style,
- const wxString& name) :
- CustomGrid(parent, id, pos, size, style, name), fileIconsAreEnabled(false)
-{}
-
-
-void CustomGridRim::updateGridSizes()
-{
- assert(getGridDataTable());
- getGridDataTable()->updateGridSizes();
-}
-
-
-xmlAccess::ColumnAttributes CustomGridRim::getDefaultColumnAttributes()
-{
- xmlAccess::ColumnAttributes defaultColumnSettings;
-
- xmlAccess::ColumnAttrib newEntry;
- newEntry.type = xmlAccess::FULL_PATH;
- newEntry.visible = false;
- newEntry.position = 0;
- newEntry.width = 150;
- defaultColumnSettings.push_back(newEntry);
-
- newEntry.type = xmlAccess::DIRECTORY;
- newEntry.position = 1;
- newEntry.width = 140;
- defaultColumnSettings.push_back(newEntry);
-
- newEntry.type = xmlAccess::REL_PATH;
- newEntry.visible = true;
- newEntry.position = 2;
- newEntry.width = 118;
- defaultColumnSettings.push_back(newEntry);
-
- newEntry.type = xmlAccess::FILENAME;
- newEntry.position = 3;
- newEntry.width = 138;
- defaultColumnSettings.push_back(newEntry);
-
- newEntry.type = xmlAccess::SIZE;
- newEntry.position = 4;
- newEntry.width = 70;
- defaultColumnSettings.push_back(newEntry);
-
- newEntry.type = xmlAccess::DATE;
- newEntry.position = 5;
- newEntry.width = 113;
- defaultColumnSettings.push_back(newEntry);
-
- newEntry.type = xmlAccess::EXTENSION;
- newEntry.visible = false;
- newEntry.position = 6;
- newEntry.width = 60;
- defaultColumnSettings.push_back(newEntry);
-
- return defaultColumnSettings;
-}
-
-
-xmlAccess::ColumnAttributes CustomGridRim::getColumnAttributes()
-{
- std::sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByPositionAndVisibility);
-
- xmlAccess::ColumnAttributes output;
- xmlAccess::ColumnAttrib newEntry;
- for (size_t i = 0; i < columnSettings.size(); ++i)
- {
- newEntry = columnSettings[i];
- if (newEntry.visible)
- newEntry.width = GetColSize(static_cast<int>(i)); //hidden columns are sorted to the end of vector!
- output.push_back(newEntry);
- }
-
- return output;
-}
-
-
-void CustomGridRim::setColumnAttributes(const xmlAccess::ColumnAttributes& attr)
-{
- //remove special alignment for column "size"
- if (GetLayoutDirection() != wxLayout_RightToLeft) //don't change for RTL languages
- for (int i = 0; i < GetNumberCols(); ++i)
- if (getTypeAtPos(i) == xmlAccess::SIZE)
- {
- wxGridCellAttr* cellAttributes = GetOrCreateCellAttr(0, i);
- cellAttributes->SetAlignment(wxALIGN_LEFT,wxALIGN_CENTRE);
- SetColAttr(i, cellAttributes);
- break;
- }
-//----------------------------------------------------------------------------------
-
- columnSettings.clear();
- if (attr.size() == 0)
- {
- //default settings:
- columnSettings = getDefaultColumnAttributes();
- }
- else
- {
- for (size_t i = 0; i < xmlAccess::COLUMN_TYPE_COUNT; ++i)
- {
- xmlAccess::ColumnAttrib newEntry;
-
- if (i < attr.size())
- newEntry = attr[i];
- else //fix corrupted data:
- {
- newEntry.type = static_cast<xmlAccess::ColumnTypes>(xmlAccess::COLUMN_TYPE_COUNT); //sort additional rows to the end
- newEntry.visible = false;
- newEntry.position = i;
- newEntry.width = 100;
- }
- columnSettings.push_back(newEntry);
- }
-
- std::sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByType);
- for (size_t i = 0; i < xmlAccess::COLUMN_TYPE_COUNT; ++i) //just be sure that each type exists only once
- columnSettings[i].type = static_cast<xmlAccess::ColumnTypes>(i);
-
- std::sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByPositionOnly);
- for (size_t i = 0; i < xmlAccess::COLUMN_TYPE_COUNT; ++i) //just be sure that positions are numbered correctly
- columnSettings[i].position = i;
- }
-
- std::sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByPositionAndVisibility);
- std::vector<xmlAccess::ColumnTypes> newPositions;
- for (size_t i = 0; i < columnSettings.size() && columnSettings[i].visible; ++i) //hidden columns are sorted to the end of vector!
- newPositions.push_back(columnSettings[i].type);
-
- //set column positions
- assert(getGridDataTable());
- getGridDataTable()->setupColumns(newPositions);
-
- //set column width (set them after setupColumns!)
- for (size_t i = 0; i < newPositions.size(); ++i)
- SetColSize(static_cast<int>(i), columnSettings[i].width);
-
-//--------------------------------------------------------------------------------------------------------
- //set special alignment for column "size"
- if (GetLayoutDirection() != wxLayout_RightToLeft) //don't change for RTL languages
- for (int i = 0; i < GetNumberCols(); ++i)
- if (getTypeAtPos(i) == xmlAccess::SIZE)
- {
- wxGridCellAttr* cellAttributes = GetOrCreateCellAttr(0, i);
- cellAttributes->SetAlignment(wxALIGN_RIGHT, wxALIGN_CENTRE);
- SetColAttr(i, cellAttributes); //make filesize right justified on grids
- break;
- }
-
- ClearSelection();
- ForceRefresh();
-}
-
-
-xmlAccess::ColumnTypes CustomGridRim::getTypeAtPos(size_t pos) const
-{
- assert(getGridDataTable());
- return getGridDataTable()->getTypeAtPos(pos);
-}
-
-
-wxString CustomGridRim::getTypeName(xmlAccess::ColumnTypes colType)
-{
- switch (colType)
- {
- case xmlAccess::FULL_PATH:
- return _("Full path");
- case xmlAccess::FILENAME:
- return _("Filename");
- case xmlAccess::REL_PATH:
- return _("Relative path");
- case xmlAccess::DIRECTORY:
- return _("Directory");
- case xmlAccess::SIZE:
- return _("Size");
- case xmlAccess::DATE:
- return _("Date");
- case xmlAccess::EXTENSION:
- return _("Extension");
- }
-
- 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());
-}
-
-
-void CustomGridRim::autoSizeColumns() //performance optimized column resizer (analog to wxGrid::AutoSizeColumns()
-{
- for (int col = 0; col < GetNumberCols(); ++col)
- {
- if (col < 0)
- return;
-
- int rowMax = -1;
- size_t lenMax = 0;
- for (int row = 0; row < GetNumberRows(); ++row)
- if (GetCellValue(row, col).size() > lenMax)
- {
- lenMax = GetCellValue(row, col).size();
- rowMax = row;
- }
-
- wxCoord extentMax = 0;
-
- //calculate width of (most likely) widest cell
- wxClientDC dc(GetGridWindow());
- if (rowMax > -1)
- {
- wxGridCellAttr* attr = GetCellAttr(rowMax, col);
- if (attr)
- {
- wxGridCellRenderer* renderer = attr->GetRenderer(this, rowMax, col);
- if (renderer)
- {
- const wxSize size = renderer->GetBestSize(*this, *attr, dc, rowMax, col);
- extentMax = std::max(extentMax, size.x);
- renderer->DecRef();
- }
- attr->DecRef();
- }
- }
-
- //consider column label
- dc.SetFont(GetLabelFont());
- wxCoord w = 0;
- wxCoord h = 0;
- dc.GetMultiLineTextExtent(GetColLabelValue(col), &w, &h );
- if (GetColLabelTextOrientation() == wxVERTICAL)
- w = h;
- extentMax = std::max(extentMax, w);
-
- extentMax += 15; //leave some space around text
-
- SetColSize(col, extentMax);
-
- }
- Refresh();
-}
-
-
-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 = static_cast<int>(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->getIconFile(currentRow);
- if (!fileName.empty())
- {
- //test if they are already loaded in buffer:
- if (FreeFileSync::IconBuffer::getInstance().requestFileIcon(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 in ms
-}
-
-
-IconUpdater::~IconUpdater() {} //non-inline destructor for std::auto_ptr to work with forward declaration
-
-
-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);
-
- //merge vectors
- newLoad.insert(newLoad.end(), iconsLeft.begin(), iconsLeft.end());
-
- FreeFileSync::IconBuffer::getInstance().setWorkload(newLoad); //attention: newLoad is invalidated after this call!!!
-
- //event.Skip();
-}
-
-//----------------------------------------------------------------------------------------
-
-
-CustomGridLeft::CustomGridLeft(wxWindow *parent,
- wxWindowID id,
- const wxPoint& pos,
- const wxSize& size,
- long style,
- const wxString& name) :
- CustomGridRim(parent, id, pos, size, style, name),
- gridDataTable(NULL) {}
-
-
-bool CustomGridLeft::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode)
-{
- //use custom wxGridTableBase class for management of large sets of formatted data.
- //This is done in CreateGrid instead of SetTable method since source code is generated and wxFormbuilder invokes CreatedGrid by default.
- gridDataTable = new CustomGridTableLeft;
- SetTable(gridDataTable, true, wxGrid::wxGridSelectRows); //give ownership to wxGrid: gridDataTable is deleted automatically in wxGrid destructor
-
- return true;
-}
-
-
-void CustomGridLeft::setGridDataTable(const GridView* gridDataView)
-{
- //set underlying grid data
- assert(gridDataTable);
- gridDataTable->setGridDataTable(gridDataView);
-}
-
-
-const CustomGridTableRim* CustomGridLeft::getGridDataTable() const
-{
- return gridDataTable;
-}
-
-
-//this method is called when grid view changes: useful for parallel updating of multiple grids
-void CustomGridLeft::alignOtherGrids(CustomGrid* gridLeft, CustomGrid* gridMiddle, CustomGrid* gridRight)
-{
- int x = 0;
- int y = 0;
- GetViewStart(&x, &y);
-
- gridMiddle->Scroll(-1, y); //scroll in y-direction only
- gridRight->Scroll(x, y);
-}
-
-
-//----------------------------------------------------------------------------------------
-CustomGridRight::CustomGridRight(wxWindow *parent,
- wxWindowID id,
- const wxPoint& pos,
- const wxSize& size,
- long style,
- const wxString& name) :
- CustomGridRim(parent, id, pos, size, style, name),
- gridDataTable(NULL) {}
-
-
-bool CustomGridRight::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode)
-{
- gridDataTable = new CustomGridTableRight;
- SetTable(gridDataTable, true, wxGrid::wxGridSelectRows); //give ownership to wxGrid: gridDataTable is deleted automatically in wxGrid destructor
-
- return true;
-}
-
-
-void CustomGridRight::setGridDataTable(const GridView* gridDataView)
-{
- //set underlying grid data
- assert(gridDataTable);
- gridDataTable->setGridDataTable(gridDataView);
-}
-
-
-const CustomGridTableRim* CustomGridRight::getGridDataTable() const
-{
- return gridDataTable;
-}
-
-
-//this method is called when grid view changes: useful for parallel updating of multiple grids
-void CustomGridRight::alignOtherGrids(CustomGrid* gridLeft, CustomGrid* gridMiddle, CustomGrid* gridRight)
-{
- 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();
-
-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,
- const wxSize& size,
- 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),
- toolTip(new CustomTooltip)
-{
- SetLayoutDirection(wxLayout_LeftToRight); //
- GetGridWindow()->SetLayoutDirection(wxLayout_LeftToRight); //avoid mirroring this dialog in RTL languages like Hebrew or Arabic
- GetGridColLabelWindow()->SetLayoutDirection(wxLayout_LeftToRight); //
-
-
- //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);
-}
-
-
-CustomGridMiddle::~CustomGridMiddle() {} //non-inline destructor for std::auto_ptr to work with forward declaration
-
-
-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;
-
- if (selectionRowBegin == -1) //change highlightning only if currently not dragging mouse
- {
- highlightedRow = mousePosToRow(event.GetPosition(), &highlightedPos);
- if (highlightedRow >= 0)
- RefreshCell(highlightedRow, 0);
- if ( highlightedRowOld >= 0 &&
- highlightedRow != highlightedRowOld)
- RefreshCell(highlightedRowOld, 0);
-
- //handle tooltip
- showToolTip(highlightedRow, GetGridWindow()->ClientToScreen(event.GetPosition()));
- }
-
- event.Skip();
-}
-
-
-void CustomGridMiddle::OnLeaveWindow(wxMouseEvent& event)
-{
- highlightedRow = -1;
- highlightedPos = BLOCKPOS_CHECK_BOX;
- Refresh();
-
- //handle tooltip
- toolTip->hide();
-}
-
-
-void CustomGridMiddle::showToolTip(int rowNumber, wxPoint pos)
-{
- const FileSystemObject* const fsObj = gridDataTable->getRawData(rowNumber);
- if (fsObj == NULL) //if invalid row...
- {
- toolTip->hide();
- return;
- }
-
- if (gridDataTable->syncPreviewIsActive()) //synchronization preview
- {
- const SyncOperation syncOp = fsObj->getSyncOperation();
- switch (syncOp)
- {
- case SO_CREATE_NEW_LEFT:
- toolTip->show(getDescription(syncOp), pos, &GlobalResources::getInstance().getImageByName(wxT("syncCreateLeftAct")));
- break;
- case SO_CREATE_NEW_RIGHT:
- toolTip->show(getDescription(syncOp), pos, &GlobalResources::getInstance().getImageByName(wxT("syncCreateRightAct")));
- break;
- case SO_DELETE_LEFT:
- toolTip->show(getDescription(syncOp), pos, &GlobalResources::getInstance().getImageByName(wxT("syncDeleteLeftAct")));
- break;
- case SO_DELETE_RIGHT:
- toolTip->show(getDescription(syncOp), pos, &GlobalResources::getInstance().getImageByName(wxT("syncDeleteRightAct")));
- break;
- case SO_OVERWRITE_LEFT:
- toolTip->show(getDescription(syncOp), pos, &GlobalResources::getInstance().getImageByName(wxT("syncDirLeftAct")));
- break;
- case SO_OVERWRITE_RIGHT:
- toolTip->show(getDescription(syncOp), pos, &GlobalResources::getInstance().getImageByName(wxT("syncDirRightAct")));
- break;
- case SO_DO_NOTHING:
- toolTip->show(getDescription(syncOp), pos, &GlobalResources::getInstance().getImageByName(wxT("syncDirNoneAct")));
- break;
- case SO_EQUAL:
- toolTip->show(getDescription(syncOp), pos, &GlobalResources::getInstance().getImageByName(wxT("equalAct")));
- break;
- case SO_UNRESOLVED_CONFLICT:
- toolTip->show(fsObj->getSyncOpConflict(), pos, &GlobalResources::getInstance().getImageByName(wxT("conflictAct")));
- break;
- };
- }
- else
- {
- const CompareFilesResult cmpRes = fsObj->getCategory();
- switch (cmpRes)
- {
- case FILE_LEFT_SIDE_ONLY:
- toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getInstance().getImageByName(wxT("leftOnlyAct")));
- break;
- case FILE_RIGHT_SIDE_ONLY:
- toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getInstance().getImageByName(wxT("rightOnlyAct")));
- break;
- case FILE_LEFT_NEWER:
- toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getInstance().getImageByName(wxT("leftNewerAct")));
- break;
- case FILE_RIGHT_NEWER:
- toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getInstance().getImageByName(wxT("rightNewerAct")));
- break;
- case FILE_DIFFERENT:
- toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getInstance().getImageByName(wxT("differentAct")));
- break;
- case FILE_EQUAL:
- toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getInstance().getImageByName(wxT("equalAct")));
- break;
- case FILE_CONFLICT:
- toolTip->show(fsObj->getCatConflict(), pos, &GlobalResources::getInstance().getImageByName(wxT("conflictAct")));
- break;
- }
- }
-}
-
-
-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 (row >= 0)
- {
- const FileSystemObject* const fsObj = gridDataTable->getRawData(row);
- if ( fsObj != NULL && //if valid row...
- gridDataTable->syncPreviewIsActive() &&
- fsObj->getSyncOperation() != SO_EQUAL) //in sync-preview equal files shall be treated as in cmp result, i.e. as full checkbox
- {
- // 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::enableSyncPreview(bool value)
-{
- assert(gridDataTable);
- gridDataTable->enableSyncPreview(value);
-
- if (value)
- GetGridColLabelWindow()->SetToolTip(_("Synchronization Preview"));
- else
- GetGridColLabelWindow()->SetToolTip(_("Comparison Result"));
-}
-
-
-void CustomGridMiddle::updateGridSizes()
-{
- assert(gridDataTable);
- gridDataTable->updateGridSizes();
-}
-
-
-void GridCellRendererMiddle::Draw(wxGrid& grid,
- wxGridCellAttr& attr,
- wxDC& dc,
- const wxRect& rect,
- int row, int col,
- bool isSelected)
-{
- //retrieve grid data
- const FileSystemObject* const fsObj = m_gridMiddle->gridDataTable->getRawData(row);
- if (fsObj != NULL) //if valid row...
- {
- if (rect.GetWidth() > CHECK_BOX_WIDTH)
- {
- const bool rowIsHighlighted = row == m_gridMiddle->highlightedRow;
-
- 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);
-
- //print checkbox into first block
- rectShrinked.SetX(rect.GetX() + 1);
-
- //HIGHLIGHTNING (checkbox):
- if ( rowIsHighlighted &&
- m_gridMiddle->highlightedPos == CustomGridMiddle::BLOCKPOS_CHECK_BOX)
- {
- if (fsObj->isActive())
- dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("checkboxTrueFocus")), rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
- else
- dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("checkboxFalseFocus")), rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
- }
- //default
- else if (fsObj->isActive())
- dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("checkboxTrue")), rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
- else
- dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("checkboxFalse")), 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 (sync direction):
- if ( rowIsHighlighted &&
- m_gridMiddle->highlightedPos != CustomGridMiddle::BLOCKPOS_CHECK_BOX) //don't allow changing direction for "=="-files
- switch (m_gridMiddle->highlightedPos)
- {
- case CustomGridMiddle::BLOCKPOS_CHECK_BOX:
- break;
- case CustomGridMiddle::BLOCKPOS_LEFT:
- dc.DrawLabel(wxEmptyString, getSyncOpImage(fsObj->testSyncOperation(true, SYNC_DIR_LEFT)), rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
- break;
- case CustomGridMiddle::BLOCKPOS_MIDDLE:
- dc.DrawLabel(wxEmptyString, getSyncOpImage(fsObj->testSyncOperation(true, SYNC_DIR_NONE)), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- break;
- case CustomGridMiddle::BLOCKPOS_RIGHT:
- dc.DrawLabel(wxEmptyString, getSyncOpImage(fsObj->testSyncOperation(true, SYNC_DIR_RIGHT)), rectShrinked, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
- break;
- }
- else //default
- {
- const wxBitmap& syncOpIcon = getSyncOpImage(fsObj->getSyncOperation());
- dc.DrawLabel(wxEmptyString, syncOpIcon, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- }
- }
- else //comparison results view
- {
- switch (fsObj->getCategory())
- {
- case FILE_LEFT_SIDE_ONLY:
- dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("leftOnlySmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- break;
- case FILE_RIGHT_SIDE_ONLY:
- dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("rightOnlySmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- break;
- case FILE_LEFT_NEWER:
- dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("leftNewerSmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- break;
- case FILE_RIGHT_NEWER:
- dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("rightNewerSmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- break;
- case FILE_DIFFERENT:
- dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("differentSmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- break;
- case FILE_EQUAL:
- dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("equalSmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- break;
- case FILE_CONFLICT:
- dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("conflictSmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- break;
- }
- }
-
- return;
- }
- }
-
- //fallback
- wxGridCellStringRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
-}
-
-
-//this method is called when grid view changes: useful for parallel updating of multiple grids
-void CustomGridMiddle::alignOtherGrids(CustomGrid* gridLeft, CustomGrid* gridMiddle, CustomGrid* gridRight)
-{
- int x = 0;
- int y = 0;
- GetViewStart(&x, &y);
- gridLeft->Scroll(-1, y);
- gridRight->Scroll(-1, y);
-}
-
-
-void CustomGridMiddle::DrawColLabel(wxDC& dc, int col)
-{
- CustomGrid::DrawColLabel(dc, col);
-
- const wxRect rect(GetColLeft(col), 0, GetColWidth(col), GetColLabelSize());
-
- if (gridDataTable->syncPreviewIsActive())
- dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("syncViewSmall")), rect, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL);
- else
- dc.DrawLabel(wxEmptyString, GlobalResources::getInstance().getImageByName(wxT("cmpViewSmall")), rect, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL);
-}
-
-
-const wxBitmap& FreeFileSync::getSyncOpImage(SyncOperation syncOp)
-{
- switch (syncOp) //evaluate comparison result and sync direction
- {
- case SO_CREATE_NEW_LEFT:
- return GlobalResources::getInstance().getImageByName(wxT("createLeftSmall"));
- case SO_CREATE_NEW_RIGHT:
- return GlobalResources::getInstance().getImageByName(wxT("createRightSmall"));
- case SO_DELETE_LEFT:
- return GlobalResources::getInstance().getImageByName(wxT("deleteLeftSmall"));
- case SO_DELETE_RIGHT:
- return GlobalResources::getInstance().getImageByName(wxT("deleteRightSmall"));
- case SO_OVERWRITE_RIGHT:
- return GlobalResources::getInstance().getImageByName(wxT("syncDirRightSmall"));
- case SO_OVERWRITE_LEFT:
- return GlobalResources::getInstance().getImageByName(wxT("syncDirLeftSmall"));
- case SO_DO_NOTHING:
- return GlobalResources::getInstance().getImageByName(wxT("syncDirNoneSmall"));
- case SO_EQUAL:
- return GlobalResources::getInstance().getImageByName(wxT("equalSmall"));
- case SO_UNRESOLVED_CONFLICT:
- return GlobalResources::getInstance().getImageByName(wxT("conflictSmall"));
- }
-
- return wxNullBitmap; //dummy
-}
-
bgstack15