void CSudokuDoc::OnEditDatabasemaintenance()
{
//Import and Export to database, remove unwanted entries from the database
CDlgMaintain dlg(m_pDB);
dlg.DoModal();
}
#pragma once
#include "afxcmn.h"
#include "afxdao.h"
#pragma warning(disable : 4995)
…
//CDlgMaintain(CWnd* pParent = NULL); //Remove the standard code, we do NOT allow this
CDlgMaintain(CDaoDatabase* pDB, CWnd* pParent = NULL);
…
private:
CDaoDatabase* m_pDB;
public:
virtual void OnOK() {};
CDlgMaintain::CDlgMaintain(CDaoDatabase* pDB, CWnd* pParent /*=NULL*/)
: CDialog(CDlgMaintain::IDD, pParent)
, m_pDB(pDB)
{
}
private:
CDaoDatabase* m_pDB;
CListCtrl m_wndList;
void PrepareColumnHeaders();
void AddData();
BOOL CDlgMaintain::OnInitDialog()
{
CDialog::OnInitDialog();
PrepareColumnHeaders(); //Columns into the list control
AddData(); //Fill from the database
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CDlgMaintain::PrepareColumnHeaders()
{
CRect rect;
m_wndList.GetClientRect(&rect);
//Width of control MINUS one fixed width column plus space for vertical scroll bar
int cx = rect.Width() - 40 - GetSystemMetrics(SM_CXVSCROLL);
m_wndList.InsertColumn(0, "ID", LVCFMT_LEFT, 40);
m_wndList.InsertColumn(1, "Game", LVCFMT_LEFT, cx); //Fills the control with this column
}
void CDlgMaintain::AddData()
{
//Remove any entries first
m_wndList.DeleteAllItems();
CDaoRecordset RS(m_pDB);
RS.Open(AFX_DAO_USE_DEFAULT_TYPE, "SELECT ID, GameDetail FROM Games ORDER BY ID");
//Just in case there are no games in the database - nothing to put in the list control
if(RS.IsBOF() && RS.IsEOF())
return;
RS.MoveFirst();
UINT nItem = -1;
while(!RS.IsEOF())
{
LVITEM lvItem = {0}; //Set all members to be zero initially
lvItem.mask = LVIF_TEXT;
lvItem.iItem = nItem;
//ID of the item in the DB, put into a string
COleVariant var = RS.GetFieldValue("ID");
CString szID;
szID.Format("%ld", var.lVal);
lvItem.pszText = szID.GetBuffer();
//nItem is the index of the newly added item
nItem = m_wndList.InsertItem(&lvItem);
//Now the game 'details'
var = RS.GetFieldValue("GameDetail");
//It is a string in the table, now convert it to a string we can use
CString szGame(var.pbVal);
m_wndList.SetItemText(nItem, 1, szGame.GetBuffer());
//Next record and increment the positioning counter for the InsertItem (so appears at end of the list control)
RS.MoveNext();
nItem++;
}
//If there are any items then select the first in the list
if(nItem >= 0)
m_wndList.SetItemState(0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
RS.Close();
}
class CSudokuDCPainter
{
public:
CSudokuDCPainter(void) {};
~CSudokuDCPainter(void) {};
void Paint(CDialog* pDlg, CDC* pDC, UINT nBoundary, CString szGame);
};
void CSudokuDCPainter::Paint(CDialog* pDlg, CDC* pDC, UINT nBoundary, CString szGame)
{
//We have a block of code in the view - with a copy/paste
//we can use that with only minor changes here (adding a pDlg->)
//for drawing the cell boundaries.
CRect rcFrame;
pDlg->GetDlgItem(nBoundary)->GetWindowRect(&rcFrame); //Get where it is to be drawn
pDlg->ScreenToClient(&rcFrame);
int iOffsetX = rcFrame.Width() / 3;
int iOffsetY = rcFrame.Height() / 3;
pDC->MoveTo(rcFrame.left + iOffsetX, rcFrame.top);
pDC->LineTo(rcFrame.left + iOffsetX, rcFrame.bottom);
pDC->MoveTo(rcFrame.left + 2*iOffsetX, rcFrame.top);
pDC->LineTo(rcFrame.left + 2*iOffsetX, rcFrame.bottom);
pDC->MoveTo(rcFrame.left, rcFrame.top + iOffsetY);
pDC->LineTo(rcFrame.right, rcFrame.top + iOffsetY);
pDC->MoveTo(rcFrame.left, rcFrame.top + 2*iOffsetY);
pDC->LineTo(rcFrame.right, rcFrame.top + 2*iOffsetY);
//Do we have a game to paint?
if(szGame.IsEmpty())
return;
//Now split into the 'digits' for display - only digits 1..9
//We did something similar for the hints in the grid button DrawItem routine
//We have an iOffsetX & Y for the 3x3 grid spacers - However we now require 9 rows
//so recalculate a miini offset inside the larger offsets
int iOffsetXmini = iOffsetX / 3;
int iOffsetYmini = iOffsetY / 3;
CRect rcClient;
CString s;
//Otherwise the digits appear with a backgound colour
pDC->SetBkMode(TRANSPARENT);
//Use the same font as the dialog, rather than the default font in the DC
CFont* pOldFont = pDC->SelectObject(pDlg->GetFont());
for(int iRow = 0; iRow < 9; iRow++)
{
//every third row reset to the internal spacers
//(remember integral math for the division, box might not be multiple of 9)
if((iRow % 3) == 0)
rcClient.top = rcFrame.top + (iRow / 3) * iOffsetY;
else
rcClient.top += iOffsetYmini;
rcClient.bottom = rcClient.top + iOffsetYmini;
for(int iCol = 0; iCol < 9; iCol++)
{
if((iCol % 3) == 0)
rcClient.left = rcFrame.left + (iCol / 3) * iOffsetX;
else
rcClient.left += iOffsetXmini;
rcClient.right = rcClient.left + iOffsetXmini;
s = szGame[iRow*9 + iCol];
//Only display if non zero
if(s.Compare("0") != 0)
pDC->DrawText(s, s.GetLength(), &rcClient, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
}
}
//reset the dc to the original - it might be reused elsewhere
pDC->SelectObject(pOldFont);
}
void CDlgMaintain::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
// Do not call CDialog::OnPaint() for painting messages
CString szGame;
//Get the selected game (if any, and also if only one selected) for painting onto this dialog
POSITION pos = m_wndList.GetFirstSelectedItemPosition();
if(pos != NULL) //Is something selected in the list
{
//Get some info about the selected item
int iIndex = m_wndList.GetNextSelectedItem(pos);
if(pos == NULL) //Must only be one selected in the list control
{
//Get the game details from the list control
szGame = m_wndList.GetItemText(iIndex, 1);
}
}
CSudokuDCPainter painter;
painter.Paint(this, &dc, IDC_STATIC_BOUNDARY, szGame);
}
void CDlgMaintain::OnLvnItemchangedList1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
}
void CDlgMaintain::OnLvnItemchangedList1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
//Force a redraw - for the details of the game
Invalidate();
}
//Force a redraw - for the details of the game
CRect rc;
GetDlgItem(IDC_STATIC_BOUNDARY)->GetWindowRect(&rc);
ScreenToClient(&rc);
InvalidateRect(rc);
void CDlgMaintain::OnBnClickedButtonDelete()
{
//Get the selected game if any, exit routine if nothing selected
POSITION pos = m_wndList.GetFirstSelectedItemPosition();
if(pos == NULL)
return;
//Ask for confirmation - there is no undo
if(AfxMessageBox(IDS_QRY_DELETE_GAMES, MB_YESNO | MB_ICONQUESTION) != IDYES)
return;
int iIndex;
CString s, szRecordKeys;
while(pos != NULL) //Is something selected in the list
{
iIndex = m_wndList.GetNextSelectedItem(pos);
s = m_wndList.GetItemText(iIndex, 0); //The ID of the game selected
szRecordKeys += s + _T(","); //Add the index and append a comma
}
//Remove the final comma from the string containing the keys
szRecordKeys.TrimRight(_T(','));
//Prepare the delete command
s.Format(_T("DELETE * FROM Games WHERE ([ID] IN (%s))"), szRecordKeys);
//Run the delete command
m_pDB->Execute(s);
//Refill the list and redisplay
AddData();
Invalidate();
}
void CDlgMaintain::OnBnClickedButtonExport()
{
//Get the selected game if any, exit routine if nothing selected
POSITION pos = m_wndList.GetFirstSelectedItemPosition();
if(pos == NULL)
return;
//Get the file name - we will use sdl (sudoku LIST) as the extension
CFileDialog dlg(FALSE //save as
, _T("sdl") //default extension
, NULL //no file name
, OFN_OVERWRITEPROMPT //if file exist warn about replacing it
, _T("Sudoku Lists (*.sdl)|*.sdl||") //Filter for the file extensions - allows only sdl file extensions
, this); //Parent window
if(dlg.DoModal() != IDOK) //display and exit function if cancel was used
return;
//open a stdio file for writing the exported items
CStdioFile file(dlg.GetPathName(), CFile::modeCreate | CFile::modeWrite);
int iIndex;
while(pos != NULL) //Is something selected in the list
{
iIndex = m_wndList.GetNextSelectedItem(pos);
file.WriteString(m_wndList.GetItemText(iIndex, 1)); //Write the 'game' into the file
//Append a carriage return new line pair IF there is another game to export after this one
if(pos != NULL)
file.WriteString(_T("\r\n"));
}
file.Close();
}
void CDlgMaintain::OnBnClickedButtonImport()
{
//Get the file name - we will use sdl (sudoku LIST) as the extension
CFileDialog dlg(TRUE //open
, _T("sdl") //default extension
, NULL //no file name
, NULL //no restrictions
, _T("Sudoku Lists (*.sdl)|*.sdl||") //Filter for the file extensions - allows only sdl file extensions
, this); //Parent window
if(dlg.DoModal() != IDOK) //display and exit function if cancel was used
return;
//open a stdio file for reading the games to import
CStdioFile file(dlg.GetPathName(), CFile::modeRead);
CString s, szSQL;
while(file.ReadString(s)) //keep reading from the file, return true if a line was read
{
szSQL.Format(_T("INSERT INTO Games (GameDetail) SELECT '%s' AS gd"), s.Left(81)); //Game is 81 chars long - removes any new line coding
try
{
m_pDB->Execute(szSQL);
}
catch(CDaoException* pe)
{
if(pe->m_pErrorInfo->m_lErrorCode != 3022) //duplicate values into a field defined as unique
{
AfxMessageBox(pe->m_pErrorInfo->m_strDescription, MB_ICONEXCLAMATION);
}
pe->Delete();
}
}
file.Close();
//Refill the list and redisplay
AddData();
Invalidate();
AfxMessageBox(_T("Import completed"));
}
int iAdded = 0, iFailed = 0;
while(file.ReadString(s)) //keep reading from the file, return true if a line was read
{
szSQL.Format(_T("INSERT INTO Games (GameDetail) SELECT '%s' AS gd"), s.Left(81)); //Game is 81 chars long - removes any new line coding
try
{
m_pDB->Execute(szSQL);
iAdded++;
}
catch(CDaoException* pe)
{
iFailed++;
if(pe->m_pErrorInfo->m_lErrorCode != 3022) //duplicate values into a field defined as unique
{
AfxMessageBox(pe->m_pErrorInfo->m_strDescription, MB_ICONEXCLAMATION);
}
pe->Delete();
}
}
file.Close();
//Refill the list and redisplay
AddData();
Invalidate();
s.Format(IDS_IMPORT_RESULTS, iAdded, iFailed);
AfxMessageBox(s);
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (0)