Объектно-ориентированное программирование Автобусы и маршруты
Содержание
Содержание _
1. Введение _
2. Постановка задачи _
3. Структура выходных и входных данных _
4. Описание основных классов _
5. Листинг программы _
6. Результат работы программы _
7. Заключение _
8. Литература _
1. Введение
Язык программирования служит двум связанным между собой целям: он дает программисту аппарат для задания действий, которые должны быть выполнены, и формирует концепции, которыми пользуется программист, размышляя о том, что делать. Первой цели идеально отвечает язык, который настолько "близок к машине", что всеми основными машинными аспектами можно легко и просто оперировать достаточно очевидным для программиста образом. С таким умыслом первоначально задумывался C. Второй цели идеально отвечает язык, который настолько "близок к решаемой задаче", чтобы концепции ее решения можно было выражать прямо и коротко. С таким умыслом предварительно задумывались средства, добавленные к C для создания C++.
Связь между языком, на котором мы думаем/программируем, и задачами и решениями, которые мы можем представлять в своем воображении, очень близка. По этой причине ограничивать свойства языка только целями исключения ошибок программиста в лучшем случае опасно. Язык предоставляет программисту набор концептуальных инструментов; если они не отвечают задаче, то их просто игнорируют. Например, серьезные ограничения концепции указателя заставляют программиста применять вектора и целую арифметику, чтобы реализовать структуры, указатели и т.п. Хорошее проектирование и отсутствие ошибок не может гарантироваться чисто за счет языковых средств. Система типов должна быть особенно полезна в нетривиальных задачах. Действительно, концепция классов в C++ показала себя мощным концептуальным средством.
2. Постановка задачи
Написать информационную систему по учёту автобусных рейсов. Информационная система должна позволять:
· Вести учет автотранспорта (преимущественно автобусного). В свою очередь следует:
· учитывать время отправления каждого автобуса;
· учитывать типы автобусов;
· привязывать автотранспорт (автобусы) к рейсам;
· Вести учет рейсов. В свою очередь следует:
· учитывать пути, составляющие рейс;
· Вести учет остановочных пунктов
Система должна обеспечить выполнение этих возможностей путем реализации алгоритмов удаления, редактирования и добавления новой информации.
При этом при удалении следует обеспечить целостность данных и выводить предупреждение пользователю в тех случаях, когда удаление информации невозможно в результате наличия связей с другими сущностями.
При добавлении необходимо разработать механизм, реализующий проверку на уникальность, который в случаях, когда необходимо соблюдать уникальность, будет предупреждать пользователя о недопустимости таких действий, а также будет препятствовать добавлению такой информации. Также необходимо обеспечить проверку на пустоту и ограничивать действия пользователя в тех случаях, когда он пытается ввести пустые значения.
При редактировании следует аналогичным образом проверять редактируемые значения проверять на уникальность.
Для реализации поставленной задачи использовать Visual Studio C++ версии не ниже 6.0. В частности применить библиотеку Microsoft Foundation Classes (MFC), представляющую интерфейс ODBC для доступа к базам данных и другие возможности.
3. Структура выходных и входных данных
Программа использует СУБД Access. В ней будет разработана основная база (bus.mdb). Разрабатываемая программа будет взаимодействовать с базой путем интерфейса MFC ODBC, что позволяет размещать данные как непосредственно на локальном компьютере, так и на любой машине в сети, предоставляющий открытый доступ к такого рода ресурсам.
База данных содержит в себе необходимое и достаточное количество нормализованных сущностей - таблиц:
· Bus - таблица, размещающая информацию об автобусах. Содержит три поля: первое - это уникальный идентификатор автобуса, однозначно определяющий его во всем множестве других автобусов, второе - тип автобуса, третье - уникальный идентификатор рейса.
|
· Path - таблица путей. Она предназначена для связи разрозненных остановочных пунктов в элементарный неделимый маршрут из одного остановочного пункта в другой. При этом направление не имеет значения. Таблица состоит из 4 полей: первое - это уникальный идентификатор пути, однозначно определяющий его во всем множестве других путей, второе и третье - уникальный идентификатор остановочного пункта, четвертое - расстояние между остановочными пунктами, выраженное во времени прохождения их из первого во второй либо из второго в первый.
|
· Race - таблица, размещающая информацию о рейсах. Имеет два поля: первое - это уникальный идентификатор рейса, однозначно определяющий его во всем множестве других рейсов, второе - описание рейса.
|
· Race items - таблица, организующая связь “многие ко многим” между таблицами Race и Path. Содержит два поля: первое - уникальный идентификатор рейса, второе - уникальный идентификатор пути.
|
· Station - таблица, размещающая информацию об остановочных пунктах автобусов. Имеет два поля - это уникальный идентификатор остановочного пункта, однозначно определяющий его во всем множестве других остановочных пунктах, и поле с его названием.
|
· Time - таблица, размещающая информацию о временах отправлений автобусов[1]. Автобусы, привязанные к одному рейсу, в течении определенного периода могут неоднократно отправляться в рейс в разные часы, что и отражается структурой данной таблицы. Таблица состоит из 3 полей: первое - это уникальный идентификатор времени, однозначно определяющий его во всем множестве других времен отправлений, второе поле - это идентификатор автобуса, свеянный с таблицей Bus (поскольку таблица Bus связанна с Time связью “один ко многим”, в Time может присутствовать несколько идентификаторов одного автобуса), третье поле - время отправления.
|
· Type - таблица, размещающая информацию о типах автобусов (классов). Имеет два поля - это уникальный идентификатор типа, однозначно определяющий его во всем множестве других типов, и поле с названием типа.
|
Схема данных представлена в таблице 1. Она отражает сущности, а также связи и их типы.
Таблица 1 - схема данных |
4. Описание основных классов
На рисунке 1 изображена диаграмма классов. Она отражает все классы проекта. Практически все классы являются пользовательскими. Они переопределены от встроенных классов путем однократного и множественного наследования.
Класс CMyDBVariant представляет собой объект, способный хранить различные типы данных. Он незаменим для работы с базой данный. Его прародителем стал класс CDBVariant. Поскольку возможностей базового класса оказалось недостаточно, пришлось его переопределить, вводя дополнительные переменные m_cstring для передачи строк типа Cstring и m_time для передачи времени типа CTime.
CMyDBRecordset – новый класс от CDBRecordset. Более гибок, нежели стандартный класс. Позволяет легко, без внедрения дополнительных переопределений, на месте, быстро создать представление сущности. В него добавлены: Count – член класса, хранящий количество записей (это сделано в силу того, что метод GetCount не возвращает реального количества), DefineRealCount – метод, определяющий Count. Также в этот класс входит fieldnames и fieldValues, позволяющий не передавать непосредственно переменные в метод DoFieldExchange а держать их прямо в классе в качестве его членов, что значительно упрощает код и способ обращения к полям представления.
Полное описание классов находиться в листинге программы.
Рисунок 1 - Диаграмма классов |
5. Листинг программы
CAboutForm.cpp
#include "stdafx.h"
#include "../main.h"
#include "CAboutForm.h"
CAboutForm::CAboutForm(CWnd* pParent):CDialog(CAboutForm::IDD,pParent){
//{{AFX_DATA_INIT(CAboutForm)
//}}AFX_DATA_INIT
}
void CAboutForm::DoDataExchange(CDataExchange* pDX){
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutForm)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutForm, CDialog)
//{{AFX_MSG_MAP(CAboutForm)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
CAboutForm.h
#if !defined(AFX_CABOUTFORM_H__09D6634D_16A6_44E9_849C_AD1B2E71646D__INCLUDED_)
#define AFX_CABOUTFORM_H__09D6634D_16A6_44E9_849C_AD1B2E71646D__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// CAboutForm.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CAboutForm dialog
class CAboutForm : public CDialog
{
// Construction
public:
CAboutForm(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CAboutForm)
enum { IDD = AboutForm };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutForm)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CAboutForm)
// NOTE: the ClassWizard will add member functions here
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_CABOUTFORM_H__09D6634D_16A6_44E9_849C_AD1B2E71646D__INCLUDED_)
CBusForm.cpp
#include "stdafx.h"
#include "../main.h"
#include "CBusForm.h"
#include "CTypeForm.h"
#include "../ExLibrary/CMyRecordset.h"
char* toString(int value,int radix=10);
CString IsEmpty_CEdit(CEdit* ctrl);
void sqlFilter(CString* value);
bool isUnique(CString sql,CString fields);
bool isRelate(CString sql,CString fields);
void Load_List(CString sql,CString fields,CListBox* ctrl,void clearIdxFunc(void),void initIdxFunc(int),void setIdxFunc(int,int));
void Load_List(CString sql,CString fields,CComboBox* ctrl,void clearIdxFunc(void),void initIdxFunc(int),void setIdxFunc(int,int));
CBusForm::CBusForm(CWnd* pParent):CDialog(CBusForm::IDD, pParent){
//{{AFX_DATA_INIT(CBusForm)
//}}AFX_DATA_INIT
}
void CBusForm::DoDataExchange(CDataExchange* pDX){
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CBusForm)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CBusForm, CDialog)
//{{AFX_MSG_MAP(CBusForm)
ON_BN_CLICKED(Button_showBusType, showBusType_onClick)
ON_BN_CLICKED(Button_DeleteBus, DeleteBus_onClick)
ON_BN_CLICKED(Button_EditBus, EditBus_onClick)
ON_BN_CLICKED(Button_AddBus, AddBus_onClick)
ON_BN_CLICKED(IDOK, OK_onClick)
ON_WM_CLOSE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/* ============================
===== User realization =====
============================ */
CListBox* pList_Bus;
CComboBox* pComboBox_BusType;
CComboBox* pComboBox_RaceInBus;
extern CDatabase DB;
extern CMyRecordset* RS;
/* ============================
====== indexes & Funcn =====
============================ */
int* pList_Bus_indexes;
int* pLBiLen;
void ClearIndexes_pList_Bus_indexes(){
if(pList_Bus_indexes){
delete []pList_Bus_indexes,pLBiLen;
pList_Bus_indexes=pLBiLen=NULL;}}
void InitIndexes_pList_Bus_indexes(int len){
pList_Bus_indexes=new int[len];
*(pLBiLen=new int)=len;}
void SetIndexes_pList_Bus_indexes(int idx,int value){
pList_Bus_indexes[idx]=value;}
int* pComboBox_BusType_indexes;
int* pCBBTiLen;
void ClearIndexes_pComboBox_BusType_indexes(){
if(pComboBox_BusType_indexes){
delete []pComboBox_BusType_indexes,pCBBTiLen;
pComboBox_BusType_indexes=pCBBTiLen=NULL;}}
void InitIndexes_pComboBox_BusType_indexes(int len){
pComboBox_BusType_indexes=new int[len];
*(pCBBTiLen=new int)=len;}
void SetIndexes_pComboBox_BusType_indexes(int idx,int value){
pComboBox_BusType_indexes[idx]=value;}
int* pComboBox_RaceInBus_indexes;
int* pCBRIBiLen;
void ClearIndexes_pComboBox_RaceInBus_indexes(){
if(pComboBox_RaceInBus_indexes){
delete []pComboBox_RaceInBus_indexes,pCBRIBiLen;
pComboBox_RaceInBus_indexes=pCBRIBiLen=NULL;}}
void InitIndexes_pComboBox_RaceInBus_indexes(int len){
pComboBox_RaceInBus_indexes=new int[len];
*(pCBRIBiLen=new int)=len;}
void SetIndexes_pComboBox_RaceInBus_indexes(int idx,int value){
pComboBox_RaceInBus_indexes[idx]=value;}
/* ============================
====== ............... =====
============================ */
void Load_List_Bus(){
Load_List("SELECT Bus.bus_ID,Trim(Str(Bus.bus_ID))+') '+Race.description+' - '+Type.name FROM Type INNER JOIN (Race INNER JOIN Bus ON Race.race_ID = Bus.race_ID) ON Type.busType_ID = Bus.busType_ID ORDER BY Trim(Str(Bus.bus_ID))+') '+Race.description+' - '+Type.name","[bus_ID]&,[Expr1001]$",
pList_Bus,
ClearIndexes_pList_Bus_indexes,
InitIndexes_pList_Bus_indexes,
SetIndexes_pList_Bus_indexes);}
void Load_ComboBox_BusType(){
Load_List("SELECT Type.* FROM Type","[busType_ID]&,[name]$",
pComboBox_BusType,
ClearIndexes_pComboBox_BusType_indexes,
InitIndexes_pComboBox_BusType_indexes,
SetIndexes_pComboBox_BusType_indexes);}
void Load_ComboBox_RaceInBus(){
Load_List("SELECT Race.race_ID,Trim(Str(Race.race_ID))+') '+Race.description FROM Race","[race_ID]&,[Expr1001]$",
pComboBox_RaceInBus,
ClearIndexes_pComboBox_RaceInBus_indexes,
InitIndexes_pComboBox_RaceInBus_indexes,
SetIndexes_pComboBox_RaceInBus_indexes);}
bool IsSelected_BusForm(){
if(pComboBox_BusType->GetCurSel()==-1||
pComboBox_RaceInBus->GetCurSel()==-1){
AfxMessageBox("Nothing selected!");
return 0;}
return 1;}
bool IsSelected_List_Bus(){
if(pList_Bus->GetCurSel()==-1){
AfxMessageBox("Nothing selected!");
return 0;}
return 1;}
void setCurSel_List_Bus(int fictionIndex){
for(int i=0;i<*pLBiLen;i++)
if(pList_Bus_indexes[i]==fictionIndex){
pList_Bus->SetCurSel(i);
return;}}
/* ============================
====== Add Edit Remove =====
============================ */
void CBusForm::AddBus_onClick(){
if(!IsSelected_BusForm())return;
// >>>
long bysType=pComboBox_BusType_indexes[pComboBox_BusType->GetCurSel()];
long raceInBus=pComboBox_RaceInBus_indexes[pComboBox_RaceInBus->GetCurSel()];
// >>>
CString insertSql="INSERT INTO Bus (busType_ID,race_ID) Values($$1,$$2)";
insertSql.Replace("$$1",toString(bysType));
insertSql.Replace("$$2",toString(raceInBus));
DB.ExecuteSQL(insertSql);
Load_List_Bus();
// :::
RS=new CMyRecordset(&DB);
CString getNewIdSql="SELECT TOP 1 Bus.bus_ID FROM Bus WHERE Bus.busType_ID=$$1 AND Bus.race_ID=$$2 ORDER BY Bus.bus_ID DESC";
getNewIdSql.Replace("$$1",toString(bysType));
getNewIdSql.Replace("$$2",toString(raceInBus));
RS->Open(getNewIdSql,"[bus_ID]&");
RS->MoveFirst();
long newId=RS->fieldsValue[0].m_lVal;
RS->Close();
delete RS;
setCurSel_List_Bus(newId);}
void CBusForm::EditBus_onClick(){
if(!IsSelected_List_Bus())return;
if(!IsSelected_BusForm())return;
// >>>
long cID=pList_Bus_indexes[pList_Bus->GetCurSel()];
long bysType=pComboBox_BusType_indexes[pComboBox_BusType->GetCurSel()];
long raceInBus=pComboBox_RaceInBus_indexes[pComboBox_RaceInBus->GetCurSel()];
// >>>
CString updateSql="UPDATE Bus SET Bus.busType_ID=$$1,Bus.race_ID=$$2 WHERE Bus.bus_ID=$$3";
updateSql.Replace("$$1",toString(bysType));
updateSql.Replace("$$2",toString(raceInBus));
updateSql.Replace("$$3",toString(cID));
DB.ExecuteSQL(updateSql);
Load_List_Bus();
setCurSel_List_Bus(cID);}
void CBusForm::DeleteBus_onClick(){
if(!IsSelected_List_Bus())return;
// >>>
long cID=pList_Bus_indexes[pList_Bus->GetCurSel()];
// >>>
CString deleteSql="DELETE Bus.*, Bus.bus_ID FROM Bus WHERE Bus.bus_ID=$$$";
deleteSql.Replace("$$$",toString(cID));
DB.ExecuteSQL(deleteSql);
long oldSel=pList_Bus->GetCurSel();
Load_List_Bus();
// :::
pList_Bus->SetCurSel(oldSel>pList_Bus->GetCount()-1?pList_Bus->GetCount()-1:oldSel);}
/* ============================
=== OnInitDialog OnClose ===
============================ */
void CBusForm::OK_onClick(){SendMessage(WM_CLOSE,0,0);}
BOOL CBusForm::OnInitDialog(){CDialog::OnInitDialog();
// >>>
pList_Bus=(CListBox*)GetDlgItem(List_Bus);
pComboBox_BusType=(CComboBox*)GetDlgItem(ComboBox_BusType);
pComboBox_RaceInBus=(CComboBox*)GetDlgItem(ComboBox_RaceInBus);
// >>>
Load_List_Bus();
Load_ComboBox_BusType();
Load_ComboBox_RaceInBus();
// >>>
return TRUE;}
void CBusForm::OnClose(){CDialog::OnClose();
ClearIndexes_pList_Bus_indexes();
ClearIndexes_pComboBox_BusType_indexes();
ClearIndexes_pComboBox_RaceInBus_indexes();}
void CBusForm::showBusType_onClick(){
CTypeForm typeForm;
typeForm.DoModal();
Load_ComboBox_BusType();}
CBusForm.h
#if !defined(AFX_CBUSFORM_H__15C9D50F_B1DF_4489_9E98_8BAF03968B1A__INCLUDED_)
#define AFX_CBUSFORM_H__15C9D50F_B1DF_4489_9E98_8BAF03968B1A__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// CBusForm.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CBusForm dialog
class CBusForm : public CDialog
{
// Construction
public:
CBusForm(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CBusForm)
enum { IDD = BusForm };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CBusForm)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CBusForm)
afx_msg void showBusType_onClick();
afx_msg void DeleteBus_onClick();
afx_msg void EditBus_onClick();
afx_msg void AddBus_onClick();
afx_msg void OK_onClick();
virtual BOOL OnInitDialog();
afx_msg void OnClose();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_CBUSFORM_H__15C9D50F_B1DF_4489_9E98_8BAF03968B1A__INCLUDED_)
CMainForm.cpp
#include "stdafx.h"
#include "../main.h"
#include "CMainForm.h"
#include "CAboutForm.h"
#include "CTimeForm.h"
#include "CStationForm.h"
#include "CPathForm.h"
#include "CRaceForm.h"
#include "CBusForm.h"
#include "../ExLibrary/CMyRecordset.h"
CMainForm::CMainForm(CWnd* pParent):CDialog(CMainForm::IDD, pParent){
//{{AFX_DATA_INIT(CMainForm)
//}}AFX_DATA_INIT
}
void CMainForm::DoDataExchange(CDataExchange* pDX){
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMainForm)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CMainForm, CDialog)
//{{AFX_MSG_MAP(CMainForm)
ON_BN_CLICKED(Button_showTime, showTime_onClick)
ON_BN_CLICKED(Button_showStation, showStation_onClick)
ON_BN_CLICKED(Button_showPath, showPath_onClick)
ON_BN_CLICKED(Button_showAbout, showAbout_onClick)
ON_BN_CLICKED(Button_showRace, showRace_onClick)
ON_BN_CLICKED(Button_showBus, showBus_onClick)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/* ============================
===== User realization =====
============================ */
void CMainForm::showTime_onClick(){
CTimeForm timeForm;
timeForm.DoModal();}
void CMainForm::showStation_onClick(){
CStationForm stationForm;
stationForm.DoModal();}
void CMainForm::showPath_onClick(){
CPathForm pathForm;
pathForm.DoModal();}
void CMainForm::showAbout_onClick(){
CAboutForm aboutForm;
aboutForm.DoModal();}
void CMainForm::showRace_onClick(){
CRaceForm raceForm;
raceForm.DoModal();}
void CMainForm::showBus_onClick(){
CBusForm busForm;
busForm.DoModal();}
BOOL CMainForm::OnInitDialog(){
CDialog::OnInitDialog();
// >>>
extern CDatabase DB;
try{
DB.Open("ODBC;DSN=");}
catch(CDBException *pError){
CString str;
str+=pError->m_strStateNativeOrigin; str+="\n"; str+=pError->m_strError;
AfxMessageBox(str);
pError->Delete();};
// >>>
return TRUE;}
CMainForm.h
#if !defined(AFX_CMAINFORM_H__43C7FDB1_2162_4824_BBAC_EAF31944B6FB__INCLUDED_)
#define AFX_CMAINFORM_H__43C7FDB1_2162_4824_BBAC_EAF31944B6FB__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// CMainForm.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CMainForm dialog
class CMainForm : public CDialog
{
// Construction
public:
CMainForm(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CMainForm)
enum { IDD = MainForm };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMainForm)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CMainForm)
afx_msg void showTime_onClick();
afx_msg void showStation_onClick();
afx_msg void showPath_onClick();
afx_msg void showAbout_onClick();
afx_msg void showRace_onClick();
afx_msg void showBus_onClick();
virtual BOOL OnInitDialog();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_CMAINFORM_H__43C7FDB1_2162_4824_BBAC_EAF31944B6FB__INCLUDED_)
CPathForm.cpp
#include "stdafx.h"
#include "../main.h"
#include "CPathForm.h"
#include "../ExLibrary/CMyRecordset.h"
char* toString(int value,int radix=10);
CString IsEmpty_CEdit(CEdit* ctrl);
void sqlFilter(CString* value);
bool isUnique(CString sql,CString fields);
bool isRelate(CString sql,CString fields);
CPathForm::CPathForm(CWnd* pParent):CDialog(CPathForm::IDD,pParent){
//{{AFX_DATA_INIT(CPathForm)
//}}AFX_DATA_INIT
}
void CPathForm::DoDataExchange(CDataExchange* pDX){
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CPathForm)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CPathForm, CDialog)
//{{AFX_MSG_MAP(CPathForm)
ON_BN_CLICKED(Button_AddPath, AddPath_onClick)
ON_BN_CLICKED(Button_EditPath, EditPath_onClick)
ON_BN_CLICKED(Button_DeletePath, DeletePath_onClick)
ON_BN_CLICKED(IDOK, OK_onClick)
ON_WM_CLOSE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/* ============================
===== User realization =====
============================ */
CListBox* pList_Pathes;
CComboBox* pComboBox_Station1;
CComboBox* pComboBox_Station2;
CEdit* pEdit_pathTime;
extern CDatabase DB;
extern CMyRecordset* RS;
/* ============================
====== indexes & Funcn =====
============================ */
int* pList_Pathes_indexes;
int* pLPiLen;
void ClearIndexes_pList_Pathes_indexes(){
if(pList_Pathes_indexes){
delete []pList_Pathes_indexes,pLPiLen;
pList_Pathes_indexes=pLPiLen=NULL;}}
void InitIndexes_pList_Pathes_indexes(int len){
pList_Pathes_indexes=new int[len];
*(pLPiLen=new int)=len;}
int* pComboBox_Stations_indexes;
int* pCBSiLen;
void ClearIndexes_pComboBox_Stations_indexes(){
if(pComboBox_Stations_indexes){
delete []pComboBox_Stations_indexes,pCBSiLen;
pComboBox_Stations_indexes=pCBSiLen=NULL;}}
void InitIndexes_pComboBox_Stations_indexes(int len){
pComboBox_Stations_indexes=new int[len];
*(pCBSiLen=new int)=len;}
/* ============================
====== ............... =====
============================ */
void Load_ComboBox_Stations(){
pComboBox_Station1->ResetContent();
pComboBox_Station2->ResetContent();
RS=new CMyRecordset(&DB);
RS->Open("SELECT Station.* FROM Station","[station_ID]&,[name]$");
RS->DefineRealCount();
ClearIndexes_pComboBox_Stations_indexes();
if(RS->Count){
InitIndexes_pComboBox_Stations_indexes(RS->Count);
for(int i=0;i<RS->Count;i++){
pComboBox_Stations_indexes[i]=RS->fieldsValue[0].m_lVal;
pComboBox_Station1->InsertString(i,RS->fieldsValue[1].m_cstring);
pComboBox_Station2->InsertString(i,RS->fieldsValue[1].m_cstring);
RS->MoveNext();}}
RS->Close();
delete RS;}
void Load_List_Pathes(){
pList_Pathes->ResetContent();
RS=new CMyRecordset(&DB);
RS->Open("SELECT Path.path_ID, Station_1.name+' <-> '+Station_2.name+' - ('+Trim(Str(Path.time))+' min)' FROM Station AS Station_2 INNER JOIN (Station AS Station_1 INNER JOIN Path ON Station_1.station_ID = Path.[start/end station_ID]) ON Station_2.station_ID = Path.[end/start station_ID] ORDER BY Station_1.name,Station_2.name,Path.time","[path_ID]&,[Expr1001]$");
RS->DefineRealCount();
ClearIndexes_pList_Pathes_indexes();
if(RS->Count){
InitIndexes_pList_Pathes_indexes(RS->Count);
for(int i=0;i<RS->Count;i++){
pList_Pathes_indexes[i]=RS->fieldsValue[0].m_lVal;
pList_Pathes->InsertString(i,RS->fieldsValue[1].m_cstring);
RS->MoveNext();}}
RS->Close();
delete RS;}
bool IsSelected_PathStations(){
if(pComboBox_Station1->GetCurSel()==-1||
pComboBox_Station2->GetCurSel()==-1){
AfxMessageBox("Nothing selected!");
return 0;}
return 1;}
bool IsSelected_List_Pathes(){
if(pList_Pathes->GetCurSel()==-1){
AfxMessageBox("Nothing selected!");
return 0;}
return 1;}
void setCurSel_PathStations(int fictionIndex){
for(int i=0;i<*pLPiLen;i++)
if(pList_Pathes_indexes[i]==fictionIndex){
pList_Pathes->SetCurSel(i);
return;}}
/* ============================
====== Add Edit Remove =====
============================ */
void CPathForm::AddPath_onClick(){
CString newValue;
if((newValue=IsEmpty_CEdit(pEdit_pathTime))=="") return;
sqlFilter(&newValue);
if(!IsSelected_PathStations())return;
// >>>
long Station1=pComboBox_Stations_indexes[pComboBox_Station1->GetCurSel()];
long Station2=pComboBox_Stations_indexes[pComboBox_Station2->GetCurSel()];
// >>>
if(Station1==Station2){
AfxMessageBox("Path can't be cycled!");
return;}
// >>>
CString prepSql="SELECT Path.path_ID FROM Path WHERE (Path.[start/end station_ID]=$$1 OR Path.[start/end station_ID]=$$2) AND (Path.[end/start station_ID]=$$1 OR Path.[end/start station_ID]=$$2) AND (Path.time=$$3)";
prepSql.Replace("$$1",toString(Station1));
prepSql.Replace("$$2",toString(Station2));
prepSql.Replace("$$3",toString(atoi(newValue)));
if(!isUnique(prepSql,"[path_ID]&"))return;
// >>>
CString insertSql="INSERT INTO Path ([start/end station_ID],[end/start station_ID],[time]) Values($$1,$$2,$$3)";
insertSql.Replace("$$1",toString(Station1));
insertSql.Replace("$$2",toString(Station2));
insertSql.Replace("$$3",toString(atoi(newValue)));
DB.ExecuteSQL(insertSql);
Load_List_Pathes();
pEdit_pathTime->SetWindowText("");
// :::
RS=new CMyRecordset(&DB);
CString getNewIdSql="SELECT Path.path_ID FROM Path WHERE Path.[start/end station_ID]=$$1 AND Path.[end/start station_ID]=$$2 AND Path.time=$$3";
getNewIdSql.Replace("$$1",toString(Station1));
getNewIdSql.Replace("$$2",toString(Station2));
getNewIdSql.Replace("$$3",toString(atoi(newValue)));
RS->Open(getNewIdSql,"[path_ID]&");
RS->MoveFirst();
long newId=RS->fieldsValue[0].m_lVal;
RS->Close();
delete RS;
setCurSel_PathStations(newId);}
void CPathForm::EditPath_onClick(){
if(!IsSelected_List_Pathes())return;
// >>>
CString newValue;
if((newValue=IsEmpty_CEdit(pEdit_pathTime))=="") return;
sqlFilter(&newValue);
if(!IsSelected_PathStations())return;
// >>>;
if((newValue=IsEmpty_CEdit(pEdit_pathTime))=="") return;
sqlFilter(&newValue);
// >>>
long Station1=pComboBox_Stations_indexes[pComboBox_Station1->GetCurSel()];
long Station2=pComboBox_Stations_indexes[pComboBox_Station2->GetCurSel()];
long cID=pList_Pathes_indexes[pList_Pathes->GetCurSel()];
// >>>
if(Station1==Station2){
AfxMessageBox("Path can't be cycled!");
return;}
// >>>
CString prepSql="SELECT Path.path_ID FROM Path WHERE (Path.[start/end station_ID]=$$1 OR Path.[start/end station_ID]=$$2) AND (Path.[end/start station_ID]=$$1 OR Path.[end/start station_ID]=$$2) AND (Path.time=$$3);";
prepSql.Replace("$$1",toString(Station1));
prepSql.Replace("$$2",toString(Station2));
prepSql.Replace("$$3",toString(atoi(newValue)));
if(!isUnique(prepSql,"[path_ID]&"))return;
// >>>
CString updateSql="UPDATE Path SET Path.[start/end station_ID]=$$1, Path.[end/start station_ID]=$$2, Path.[time]=$$3 WHERE Path.path_ID=$$4";
updateSql.Replace("$$1",toString(Station1));
updateSql.Replace("$$2",toString(Station2));
updateSql.Replace("$$3",newValue);
updateSql.Replace("$$4",toString(cID));
DB.ExecuteSQL(updateSql);
Load_List_Pathes();
pEdit_pathTime->SetWindowText("");
setCurSel_PathStations(cID);}
void CPathForm::DeletePath_onClick(){
if(!IsSelected_List_Pathes())return;
// >>>
long cID=pList_Pathes_indexes[pList_Pathes->GetCurSel()];
// >>>
CString relateTestSql="SELECT [Race items].race_ID FROM [Race items] WHERE [Race items].path_ID=$$$";
relateTestSql.Replace("$$$",toString(cID));
if(isRelate(relateTestSql,"[race_ID]&"))return;
// >>>
CString deleteSql="DELETE Path.* FROM Path WHERE Path.path_ID=$$$";
deleteSql.Replace("$$$",toString(cID));
DB.ExecuteSQL(deleteSql);
long oldSel=pList_Pathes->GetCurSel();
Load_List_Pathes();
// :::
pList_Pathes->SetCurSel(oldSel>pList_Pathes->GetCount()-1?pList_Pathes->GetCount()-1:oldSel);}
/* ============================
=== OnInitDialog OnClose ===
============================ */
void CPathForm::OK_onClick(){SendMessage(WM_CLOSE,0,0);}
BOOL CPathForm::OnInitDialog(){CDialog::OnInitDialog();
// >>>
pList_Pathes=(CListBox*)GetDlgItem(List_Pathes);
pComboBox_Station1=(CComboBox*)GetDlgItem(ComboBox_Station1);
pComboBox_Station2=(CComboBox*)GetDlgItem(ComboBox_Station2);
pEdit_pathTime=(CEdit*)GetDlgItem(Edit_pathTime);
// >>>
Load_ComboBox_Stations();
Load_List_Pathes();
// >>>
return TRUE;}
void CPathForm::OnClose(){CDialog::OnClose();
ClearIndexes_pComboBox_Stations_indexes();
ClearIndexes_pList_Pathes_indexes();}
CPathForm.h
#if !defined(AFX_CPATHFORM_H__ADDA99DE_4EF9_466B_8617_713613F3161E__INCLUDED_)
#define AFX_CPATHFORM_H__ADDA99DE_4EF9_466B_8617_713613F3161E__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// CPathForm.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CPathForm dialog
class CPathForm : public CDialog
{
// Construction
public:
CPathForm(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CPathForm)
enum { IDD = PathForm };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CPathForm)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CPathForm)
afx_msg void AddPath_onClick();
afx_msg void EditPath_onClick();
afx_msg void DeletePath_onClick();
afx_msg void OK_onClick();
virtual BOOL OnInitDialog();
afx_msg void OnClose();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_CPATHFORM_H__ADDA99DE_4EF9_466B_8617_713613F3161E__INCLUDED_)
CRaceForm.cpp
#include "stdafx.h"
#include "../main.h"
#include "CRaceForm.h"
#include "../ExLibrary/CMyRecordset.h"
char* toString(int value,int radix=10);
CString IsEmpty_CEdit(CEdit* ctrl);
void sqlFilter(CString* value);
bool isUnique(CString sql,CString fields);
bool isRelate(CString sql,CString fields);
void Load_List(CString sql,CString fields,CListBox* ctrl,void clearIdxFunc(void),void initIdxFunc(int),void setIdxFunc(int,int));
CRaceForm::CRaceForm(CWnd* pParent):CDialog(CRaceForm::IDD,pParent){
//{{AFX_DATA_INIT(CRaceForm)
//}}AFX_DATA_INIT
}
void CRaceForm::DoDataExchange(CDataExchange* pDX){
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CRaceForm)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CRaceForm, CDialog)
//{{AFX_MSG_MAP(CRaceForm)
ON_BN_CLICKED(Button_AddRace, AddRace_onClick)
ON_BN_CLICKED(Button_EditRace, EditRace_onClick)
ON_BN_CLICKED(Button_DeleteRace, DeleteRace_onClick)
ON_BN_CLICKED(IDOK, OK_onClick)
ON_WM_CLOSE()
ON_BN_CLICKED(Button_toAcceptPath, toAcceptPath_onCLick)
ON_BN_CLICKED(Button_toFreePath, toFreePath_onClick)
ON_LBN_SELCHANGE(Race_List, SelchangeList_onSelectChange)
ON_LBN_SELCHANGE(List_AcceptPath, AcceptPath_onSelchange)
ON_LBN_SELCHANGE(List_FreePath, FreePath_onSelchange)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/* ============================
===== User realization =====
============================ */
CListBox* pRace_List;
CEdit* pEdit_race;
CListBox* pList_AcceptPath;
CListBox* pList_FreePath;
extern CDatabase DB;
extern CMyRecordset* RS;
/* ============================
====== indexes & Funcn =====
============================ */
int* pRace_List_indexes;
int* pRLiLen;
void ClearIndexes_pRace_List_indexes(){
if(pRace_List_indexes){
delete []pRace_List_indexes,pRLiLen;
pRace_List_indexes=pRLiLen=NULL;}}
void InitIndexes_pRace_List_indexes(int len){
pRace_List_indexes=new int[len];
*(pRLiLen=new int)=len;}
int* pList_AcceptPath_indexes;
int* pLAPiLen;
void ClearIndexes_pList_AcceptPath_indexes(){
if(pList_AcceptPath_indexes){
delete []pList_AcceptPath_indexes,pLAPiLen;
pList_AcceptPath_indexes=pLAPiLen=NULL;}}
void InitIndexes_pList_AcceptPath_indexes(int len){
pList_AcceptPath_indexes=new int[len];
*(pLAPiLen=new int)=len;}
void SetIndexes_pList_AcceptPath_indexes(int idx,int value){
pList_AcceptPath_indexes[idx]=value;}
int* pList_FreePath_indexes;
int* pLFPiLen;
void ClearIndexes_pList_FreePath_indexes(){
if(pList_FreePath_indexes){
delete []pList_FreePath_indexes,pLFPiLen;
pList_FreePath_indexes=pLFPiLen=NULL;}}
void InitIndexes_pList_FreePath_indexes(int len){
pList_FreePath_indexes=new int[len];
*(pLFPiLen=new int)=len;}
void SetIndexes_pList_FreePath_indexes(int idx,int value){
pList_FreePath_indexes[idx]=value;}
/* ============================
====== ............... =====
============================ */
void Load_Race_List(){
pRace_List->ResetContent();
RS=new CMyRecordset(&DB);
RS->Open("SELECT Race.race_ID, Str(Race.race_ID)+') '+Race.description FROM Race ORDER BY Race.description","[race_ID]&,[Expr1001]$");
RS->DefineRealCount();
ClearIndexes_pRace_List_indexes();
if(RS->Count){
InitIndexes_pRace_List_indexes(RS->Count);
for(int i=0;i<RS->Count;i++){
pRace_List_indexes[i]=RS->fieldsValue[0].m_lVal;
pRace_List->InsertString(i,RS->fieldsValue[1].m_cstring);
RS->MoveNext();}}
RS->Close();
delete RS;}
bool IsSelected_Race_List(){
if(pRace_List->GetCurSel()==-1){
AfxMessageBox("Nothing selected!");
return 0;}
return 1;}
void setCurSel_Race_List(int fictionIndex){
for(int i=0;i<*pRLiLen;i++)
if(pRace_List_indexes[i]==fictionIndex){
pRace_List->SetCurSel(i);
return;}}
/* ============================
====== Add Edit Remove =====
============================ */
void CRaceForm::AddRace_onClick(){
CString newValue;
if((newValue=IsEmpty_CEdit(pEdit_race))=="") return;
sqlFilter(&newValue);
// >>>
CString prepSql="SELECT Race.race_ID FROM Race WHERE Race.description='$$$'";
prepSql.Replace("$$$",newValue);
if(!isUnique(prepSql,"[race_ID]&"))return;
// >>>
CString insertSql="INSERT INTO Race (description) Values('$$$')";
insertSql.Replace("$$$",newValue);
DB.ExecuteSQL(insertSql);
Load_Race_List();
pEdit_race->SetWindowText("");
// :::
RS=new CMyRecordset(&DB);
CString getNewIdSql="SELECT Race.race_ID FROM Race WHERE Race.description='$$1'";
getNewIdSql.Replace("$$1",newValue);
RS->Open(getNewIdSql,"[race_ID]&");
RS->MoveFirst();
long newId=RS->fieldsValue[0].m_lVal;
RS->Close();
delete RS;
setCurSel_Race_List(newId);
this->SelchangeList_onSelectChange();}
void CRaceForm::EditRace_onClick(){
if(!IsSelected_Race_List())return;
long cID=pRace_List_indexes[pRace_List->GetCurSel()];
// >>>
CString newValue;
if((newValue=IsEmpty_CEdit(pEdit_race))=="") return;
sqlFilter(&newValue);
// >>>
CString prepSql="SELECT Race.race_ID FROM Race WHERE Race.description='$$$'";
prepSql.Replace("$$$",newValue);
if(!isUnique(prepSql,"[race_ID]&"))return;
// >>>
CString updateSql="UPDATE Race SET Race.description='$$1' WHERE Race.race_ID=$$2";
updateSql.Replace("$$1",newValue);
updateSql.Replace("$$2",toString(cID));
DB.ExecuteSQL(updateSql);
Load_Race_List();
pEdit_race->SetWindowText("");
setCurSel_Race_List(cID);}
void CRaceForm::DeleteRace_onClick(){
if(!IsSelected_Race_List())return;
long cID=pRace_List_indexes[pRace_List->GetCurSel()];
// >>>
CString relateTestSql="SELECT Bus.bus_ID FROM Bus WHERE Bus.race_ID=$$$";
relateTestSql.Replace("$$$",toString(cID));
if(isRelate(relateTestSql,"[bus_ID]&"))return;
// >>>
CString deleteSql="DELETE Race.* FROM Race WHERE Race.race_ID=$$$";
deleteSql.Replace("$$$",toString(cID));
DB.ExecuteSQL(deleteSql);
long oldSel=pRace_List->GetCurSel();
Load_Race_List();
pRace_List->SetCurSel(oldSel>pRace_List->GetCount()-1?pRace_List->GetCount()-1:oldSel);
this->SelchangeList_onSelectChange();}
/* ============================
======= Accept pathes ======
============================ */
void CRaceForm::AcceptPath_onSelchange(){pList_FreePath->SetCurSel(-1);}
void CRaceForm::FreePath_onSelchange(){pList_AcceptPath->SetCurSel(-1);}
CString sh1Sql="SELECT Path.path_ID, Station_1.name+' < - > '+Station_2.name FROM Station AS Station_2 INNER JOIN ((Station AS Station_1 INNER JOIN PAth ON Station_1.station_ID = PAth.[start/end station_ID]) INNER JOIN [Race items] ON Path.path_ID = [Race items].path_ID) ON Station_2.station_ID = Path.[end/start station_ID] WHERE [Race items].race_ID = $$1 ORDER BY Station_1.name+' < - > '+Station_2.name";
CString sh2Sql="SELECT PAth.path_ID, Station_1.name+' < - > '+Station_2.name FROM Station AS Station_2 INNER JOIN ((Station AS Station_1 INNER JOIN PAth ON Station_1.station_ID = PAth.[start/end station_ID]) LEFT JOIN [Race items] ON PAth.path_ID = [Race items].path_ID) ON Station_2.station_ID = PAth.[end/start station_ID] WHERE [Race items].race_ID <> $$1 Or [Race items].race_ID Is Null ORDER BY Station_1.name+' < - > '+Station_2.name";
void Load_List_AcceptPath(long cID){
CString tmpSql(sh1Sql);
tmpSql.Replace("$$1",toString(cID));
Load_List(tmpSql,"[path_ID]&,[Expr1001]$",pList_AcceptPath,ClearIndexes_pList_AcceptPath_indexes,InitIndexes_pList_AcceptPath_indexes,SetIndexes_pList_AcceptPath_indexes);}
void Load_List_FreePath(long cID){
CString tmpSql(sh2Sql);
tmpSql.Replace("$$1",toString(cID));
Load_List(tmpSql,"[path_ID]&,[Expr1001]$",pList_FreePath,ClearIndexes_pList_FreePath_indexes,InitIndexes_pList_FreePath_indexes,SetIndexes_pList_FreePath_indexes);}
void CRaceForm::toAcceptPath_onCLick(){
long cFictionID=pList_FreePath->GetCurSel();
// ===
if(cFictionID==-1){
AfxMessageBox("Nothing selected!");
return;}
// >>>
CString prepSql="INSERT INTO [Race items] (race_ID,path_ID) Values($$1,$$2)";
prepSql.Replace("$$1",toString(pRace_List_indexes[pRace_List->GetCurSel()]));
prepSql.Replace("$$2",toString(pList_FreePath_indexes[cFictionID]));
DB.ExecuteSQL(prepSql);
// >>>
long cRaceID=pRace_List_indexes[pRace_List->GetCurSel()];
Load_List_AcceptPath(cRaceID);
Load_List_FreePath(cRaceID);}
void CRaceForm::toFreePath_onClick(){
long cFictionID=pList_AcceptPath->GetCurSel();
// ===
if(cFictionID==-1){
AfxMessageBox("Nothing selected!");
return;}
// >>>
CString prepSql="DELETE [Race items].* FROM [Race items] WHERE [Race items].path_ID=$$$";
prepSql.Replace("$$$",toString(pList_AcceptPath_indexes[cFictionID]));
DB.ExecuteSQL(prepSql);
// >>>
long cRaceID=pRace_List_indexes[pRace_List->GetCurSel()];
Load_List_AcceptPath(cRaceID);
Load_List_FreePath(cRaceID);}
void CRaceForm::SelchangeList_onSelectChange(){
if(pRace_List->GetCurSel()==-1)return;
long cID=pRace_List_indexes[pRace_List->GetCurSel()];
// >>>
Load_List_AcceptPath(cID);
Load_List_FreePath(cID);}
/* ============================
=== OnInitDialog OnClose ===
============================ */
void CRaceForm::OK_onClick(){SendMessage(WM_CLOSE,0,0);}
BOOL CRaceForm::OnInitDialog(){CDialog::OnInitDialog();
// >>>
pRace_List=(CListBox*)GetDlgItem(Race_List);
pEdit_race=(CEdit*)GetDlgItem(Edit_race);
// ===
pList_AcceptPath=(CListBox*)GetDlgItem(List_AcceptPath);
pList_FreePath=(CListBox*)GetDlgItem(List_FreePath);
// >>>
Load_Race_List();
// >>>
return TRUE;}
void CRaceForm::OnClose(){CDialog::OnClose();
ClearIndexes_pRace_List_indexes();
ClearIndexes_pList_AcceptPath_indexes();
ClearIndexes_pList_FreePath_indexes();}
CRaceForm.h
#if !defined(AFX_CRACEFORM_H__4F7EEA3A_E810_4324_9EAE_F11652E482D3__INCLUDED_)
#define AFX_CRACEFORM_H__4F7EEA3A_E810_4324_9EAE_F11652E482D3__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// CRaceForm.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CRaceForm dialog
class CRaceForm : public CDialog
{
// Construction
public:
CRaceForm(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CRaceForm)
enum { IDD = RaceForm };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CRaceForm)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CRaceForm)
afx_msg void AddRace_onClick();
afx_msg void EditRace_onClick();
afx_msg void DeleteRace_onClick();
afx_msg void OK_onClick();
virtual BOOL OnInitDialog();
afx_msg void OnClose();
afx_msg void toAcceptPath_onCLick();
afx_msg void toFreePath_onClick();
afx_msg void SelchangeList_onSelectChange();
afx_msg void AcceptPath_onSelchange();
afx_msg void FreePath_onSelchange();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_CRACEFORM_H__4F7EEA3A_E810_4324_9EAE_F11652E482D3__INCLUDED_)
CStationForm.cpp
#include "stdafx.h"
#include "../main.h"
#include "CStationForm.h"
#include "../ExLibrary/CMyRecordset.h"
char* toString(int value,int radix=10);
CString IsEmpty_CEdit(CEdit* ctrl);
void sqlFilter(CString* value);
bool isUnique(CString sql,CString fields);
bool isRelate(CString sql,CString fields);
CStationForm::CStationForm(CWnd* pParent):CDialog(CStationForm::IDD,pParent){
//{{AFX_DATA_INIT(CStationForm)
//}}AFX_DATA_INIT
}
void CStationForm::DoDataExchange(CDataExchange* pDX){
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CStationForm)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CStationForm, CDialog)
//{{AFX_MSG_MAP(CStationForm)
ON_BN_CLICKED(Button_AddStation, AddStation_onClick)
ON_BN_CLICKED(Button_EditStation, EditStation_onClick)
ON_BN_CLICKED(Button_DeleteStation, DeleteStation_onClick)
ON_BN_CLICKED(IDOK, OK_onClick)
ON_WM_CLOSE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/* ============================
===== User realization =====
============================ */
CListBox* pList_Station;
CEdit* pEdit_station;
extern CDatabase DB;
extern CMyRecordset* RS;
/* ============================
====== indexes & Funcn =====
============================ */
int* pList_Station_indexes;
int* pLSiLen;
void ClearIndexes_pList_Station_indexes(){
if(pList_Station_indexes){
delete []pList_Station_indexes,pLSiLen;
pList_Station_indexes=pLSiLen=NULL;}}
void InitIndexes_pList_Station_indexes(int len){
pList_Station_indexes=new int[len];
*(pLSiLen=new int)=len;}
/* ============================
====== Add Edit Remove =====
============================ */
void Load_List_Station(){
pList_Station->ResetContent();
RS=new CMyRecordset(&DB);
RS->Open("SELECT * FROM Station ORDER BY name","[station_ID]&,[name]$");
RS->DefineRealCount();
if(RS->Count){
InitIndexes_pList_Station_indexes(RS->Count);
for(int i=0;i<RS->Count;i++){
pList_Station_indexes[i]=RS->fieldsValue[0].m_lVal;
pList_Station->InsertString(i,RS->fieldsValue[1].m_cstring);
RS->MoveNext();}}
RS->Close();
delete RS;}
void setCurSel_StationForm(int fictionIndex){
for(int i=0;i<*pLSiLen;i++)
if(pList_Station_indexes[i]==fictionIndex){
pList_Station->SetCurSel(i);
return;}}
bool IsSelected_StationForm(){
if(pList_Station->GetCurSel()==-1){
AfxMessageBox("Nothing selected!");
return 0;}
return 1;}
/* ============================
====== ............... =====
============================ */
void CStationForm::AddStation_onClick(){
CString newValue;
if((newValue=IsEmpty_CEdit(pEdit_station))=="") return;
sqlFilter(&newValue);
// >>>
CString prepSql="SELECT name From Station WHERE name='$$$'";
prepSql.Replace("$$$",newValue);
if(!isUnique(prepSql,"[name]$"))return;
// >>>
CString insertSql="INSERT INTO Station (name) Values('$$$')";
insertSql.Replace("$$$",newValue);
DB.ExecuteSQL(insertSql);
Load_List_Station();
pEdit_station->SetWindowText("");
// :::
RS=new CMyRecordset(&DB);
CString getNewIdSql="SELECT station_ID From Station WHERE name='$$$'";
getNewIdSql.Replace("$$$",newValue);
RS->Open(getNewIdSql,"[station_ID]&");
RS->MoveFirst();
long newId=RS->fieldsValue[0].m_lVal;
RS->Close();
delete RS;
setCurSel_StationForm(newId);}
void CStationForm::EditStation_onClick(){
if(!IsSelected_StationForm())return;
int cID=pList_Station_indexes[pList_Station->GetCurSel()];
// >>>
CString newValue;
if((newValue=IsEmpty_CEdit(pEdit_station))=="") return;
sqlFilter(&newValue);
// >>>
CString prepSql="SELECT name From Station WHERE name='$$$'";
prepSql.Replace("$$$",newValue);
if(!isUnique(prepSql,"[name]$"))return;
// >>>
CString updateSql="UPDATE Station SET Station.name = '$$1' WHERE station_ID=$$2";
updateSql.Replace("$$1",newValue);
updateSql.Replace("$$2",toString(cID));
DB.ExecuteSQL(updateSql);
Load_List_Station();
pEdit_station->SetWindowText("");
// :::
setCurSel_StationForm(cID);}
void CStationForm::DeleteStation_onClick(){
if(!IsSelected_StationForm())return;
int cID=pList_Station_indexes[pList_Station->GetCurSel()];
// >>>
CString relateTestSql="SELECT path_ID FROM path WHERE [start/end station_ID]=$$$ OR [end/start station_ID]=$$$";
relateTestSql.Replace("$$$",toString(cID));
if(isRelate(relateTestSql,"[station_ID]&"))return;
// >>>
CString deleteSql="DELETE * FROM Station WHERE station_ID=";
deleteSql+=toString(cID);
DB.ExecuteSQL(deleteSql);
int oldSel=pList_Station->GetCurSel();
Load_List_Station();
// :::
pList_Station->SetCurSel(oldSel>pList_Station->GetCount()-1?pList_Station->GetCount()-1:oldSel);}
/* ============================
=== OnInitDialog OnClose ===
============================ */
void CStationForm::OK_onClick(){SendMessage(WM_CLOSE,0,0);}
BOOL CStationForm::OnInitDialog(){CDialog::OnInitDialog();
// >>>
pList_Station=(CListBox*)GetDlgItem(List_Station);
pEdit_station=(CEdit*)GetDlgItem(Edit_station);
// >>>
Load_List_Station();
return TRUE;}
void CStationForm::OnClose(){CDialog::OnClose();
ClearIndexes_pList_Station_indexes();}
CStationForm.cpp
#if !defined(AFX_CSTATIONFORM_H__446D119D_055C_445F_8865_161D473D2E2E__INCLUDED_)
#define AFX_CSTATIONFORM_H__446D119D_055C_445F_8865_161D473D2E2E__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// CStationForm.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CStationForm dialog
class CStationForm : public CDialog
{
// Construction
public:
CStationForm(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CStationForm)
enum { IDD = StationForm };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CStationForm)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CStationForm)
afx_msg void AddStation_onClick();
afx_msg void EditStation_onClick();
afx_msg void DeleteStation_onClick();
afx_msg void OK_onClick();
virtual BOOL OnInitDialog();
afx_msg void OnClose();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_CSTATIONFORM_H__446D119D_055C_445F_8865_161D473D2E2E__INCLUDED_)
CTimeForm.cpp
#include "stdafx.h"
#include "../main.h"
#include "CTimeForm.h"
#include "../ExLibrary/CMyRecordset.h"
char* toString(int value,int radix=10);
bool isUnique(CString sql,CString fields);
CTimeForm::CTimeForm(CWnd* pParent):CDialog(CTimeForm::IDD,pParent){
//{{AFX_DATA_INIT(CTimeForm)
//}}AFX_DATA_INIT
}
void CTimeForm::DoDataExchange(CDataExchange* pDX){
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CTimeForm)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CTimeForm, CDialog)
//{{AFX_MSG_MAP(CTimeForm)
ON_BN_CLICKED(Button_timesHelp, timesHelp_onClick)
ON_BN_CLICKED(Button_AddTime, AddTime_onClick)
ON_BN_CLICKED(Button_EditTime, EditTime_onClick)
ON_BN_CLICKED(Button_DeleteTime, DeleteTime_onClick)
ON_BN_CLICKED(IDOK, OK_onClick)
ON_WM_CLOSE()
ON_CBN_SELCHANGE(ComboBox_BusList, SelchangeBusList_onChange)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/* ============================
===== User realization =====
============================ */
CListBox* pList_Time;
CComboBox* pComboBox_BusList;
CComboBox* pComboBox_TimeH;
CComboBox* pComboBox_TimeM;
extern CDatabase DB;
extern CMyRecordset* RS;
/* ============================
====== indexes & Funcn =====
============================ */
int* pList_Time_indexes;
int* pLTiLen;
void ClearIndexes_pList_Time_indexes(){
if(pList_Time_indexes){
delete []pList_Time_indexes,pLTiLen;
pList_Time_indexes=pLTiLen=NULL;}}
void InitIndexes_pList_Time_indexes(int len){
pList_Time_indexes=new int[len];
*(pLTiLen=new int)=len;}
int* pComboBox_BusList_indexes;
int* pCBBiLen;
void ClearIndexes_pComboBox_BusList_indexes(){
if(pComboBox_BusList_indexes){
delete []pComboBox_BusList_indexes,pLTiLen;
pComboBox_BusList_indexes=pCBBiLen=NULL;}}
void InitIndexes_pComboBox_BusList_indexes(int len){
pComboBox_BusList_indexes=new int[len];
*(pCBBiLen=new int)=len;}
/* ============================
====== ............... =====
============================ */
void Load_List_Time(int busID){
pList_Time->ResetContent();
RS=new CMyRecordset(&DB);
CString selectSql="SELECT Time.time_ID,Time.time FROM [Time] WHERE Time.bus_ID=$$$ ORDER BY Time.time;"; selectSql.Replace("$$$",toString(busID));
RS->Open(selectSql,"[time_ID]&,[time]&");
RS->DefineRealCount();
ClearIndexes_pList_Time_indexes();
if(RS->Count){
InitIndexes_pList_Time_indexes(RS->Count);
for(int i=0;i<RS->Count;i++){
pList_Time_indexes[i]=RS->fieldsValue[0].m_lVal;
CString Time,buf1,buf2;
buf1+="0"; buf1+=toString((int)RS->fieldsValue[1].m_lVal/60);
buf2+="0"; buf2+=toString((int)RS->fieldsValue[1].m_lVal%60);
Time+=buf1.Right(2); Time+=":";
Time+=buf2.Right(2);
pList_Time->InsertString(i,Time);
RS->MoveNext();}}
RS->Close();
delete RS;}
void Load_ComboBox_BusList(){
pComboBox_BusList->ResetContent();
RS=new CMyRecordset(&DB);
CString selectSql="SELECT Bus.bus_ID,Type.name,Race.description FROM Race INNER JOIN (Type INNER JOIN Bus ON Type.busType_ID = Bus.busType_ID) ON Race.race_ID = Bus.race_ID ORDER BY Type.name,Race.description";
RS->Open(selectSql,"[bus_ID]&,[name]$,[description]$");
RS->DefineRealCount();
ClearIndexes_pComboBox_BusList_indexes();
if(RS->Count){
InitIndexes_pComboBox_BusList_indexes(RS->Count);
for(int i=0;i<RS->Count;i++){
CString buf;
buf+=toString(RS->fieldsValue[0].m_lVal); buf+=") class: ";
buf+=RS->fieldsValue[1].m_cstring; buf+="; race: ";
buf+=RS->fieldsValue[2].m_cstring;
pComboBox_BusList_indexes[i]=RS->fieldsValue[0].m_lVal;
pComboBox_BusList->InsertString(i,buf);
RS->MoveNext();}}
RS->Close();
delete RS;}
bool IsSelected_Time(){
if(pList_Time->GetCurSel()==-1){
AfxMessageBox("Nothing selected!");
return 0;}
return 1;}
bool IsEmpty_List_Time(){
if(pComboBox_TimeH->GetCurSel()==-1||
pComboBox_TimeM->GetCurSel()==-1){
AfxMessageBox("No selected hour or min.!");
return 0;}
return 1;}
void setCurSel_List_Time(int fictionIndex){
for(int i=0;i<*pLTiLen;i++)
if(pList_Time_indexes[i]==fictionIndex){
pList_Time->SetCurSel(i);
return;}}
/* ============================
====== Add Edit Remove =====
============================ */
void CTimeForm::AddTime_onClick(){
if(pComboBox_BusList->GetCurSel()==-1){
AfxMessageBox("No selected bus!");
return;}
// >>>
if(!IsEmpty_List_Time())return;
// >>>
long newValue=pComboBox_TimeH->GetCurSel()*60+
pComboBox_TimeM->GetCurSel();
long busID=pComboBox_BusList_indexes[pComboBox_BusList->GetCurSel()];
// >>>
CString prepSql="SELECT Time.time FROM [Time] WHERE Time.bus_ID=$$1 AND Time.time=$$2";
prepSql.Replace("$$1",toString(busID));
prepSql.Replace("$$2",toString(newValue));
if(!isUnique(prepSql,"[time]&"))return;
// >>>
CString insertSql="INSERT INTO [Time] (bus_ID,[time]) Values($$1,$$2)";
insertSql.Replace("$$1",toString(busID));
insertSql.Replace("$$2",toString(newValue));
DB.ExecuteSQL(insertSql);
Load_List_Time(busID);
// :::
RS=new CMyRecordset(&DB);
CString getNewIdSql="SELECT Time.time_ID FROM [Time] WHERE Time.bus_ID=$$1 AND Time.time=$$2";
getNewIdSql.Replace("$$1",toString(busID));
getNewIdSql.Replace("$$2",toString(newValue));
RS->Open(getNewIdSql,"[time_ID]&");
RS->MoveFirst();
long newId=RS->fieldsValue[0].m_lVal;
RS->Close();
delete RS;
setCurSel_List_Time(newId);}
void CTimeForm::EditTime_onClick(){
if(!IsSelected_Time())return;
if(!IsEmpty_List_Time())return;
// >>>
long newValue=pComboBox_TimeH->GetCurSel()*60+
pComboBox_TimeM->GetCurSel();
long busID=pComboBox_BusList_indexes[pComboBox_BusList->GetCurSel()];
long cID=pList_Time_indexes[pList_Time->GetCurSel()];
// >>>
CString prepSql="SELECT Time.time FROM [Time] WHERE Time.bus_ID=$$1 AND Time.time=$$2";
prepSql.Replace("$$1",toString(busID));
prepSql.Replace("$$2",toString(newValue));
if(!isUnique(prepSql,"[time]&"))return;
// >>>
CString updateSql="UPDATE [Time] SET [Time].bus_ID=$$1,[Time].[time]=$$2 WHERE Time.time_ID=$$3";
updateSql.Replace("$$1",toString(busID));
updateSql.Replace("$$2",toString(newValue));
updateSql.Replace("$$3",toString(cID));
DB.ExecuteSQL(updateSql);
Load_List_Time(busID);
setCurSel_List_Time(cID);}
void CTimeForm::DeleteTime_onClick(){
if(!IsSelected_Time())return;
long busID=pComboBox_BusList_indexes[pComboBox_BusList->GetCurSel()];
long cID=pList_Time_indexes[pList_Time->GetCurSel()];
// >>>
CString deleteSql="DELETE Time.* FROM [Time] WHERE Time.time_ID=";
deleteSql+=toString(cID);
int oldSel=pList_Time->GetCurSel();
DB.ExecuteSQL(deleteSql);
Load_List_Time(busID);
pList_Time->SetCurSel(oldSel>pList_Time->GetCount()-1?pList_Time->GetCount()-1:oldSel);}
void CTimeForm::timesHelp_onClick(){
AfxMessageBox("One bus = only one race! One race - can be many bus!");}
/* ============================
=== OnInitDialog OnClose ===
============================ */
void CTimeForm::OK_onClick(){SendMessage(WM_CLOSE,0,0);}
BOOL CTimeForm::OnInitDialog(){CDialog::OnInitDialog();
// >>>
pList_Time=(CListBox*)GetDlgItem(List_Time);
pComboBox_BusList=(CComboBox*)GetDlgItem(ComboBox_BusList);
pComboBox_TimeH=(CComboBox*)GetDlgItem(ComboBox_TimeH);
pComboBox_TimeM=(CComboBox*)GetDlgItem(ComboBox_TimeM);
Load_ComboBox_BusList();
// >>>
return TRUE;}
void CTimeForm::OnClose(){CDialog::OnClose();
ClearIndexes_pList_Time_indexes();
ClearIndexes_pComboBox_BusList_indexes();}
void CTimeForm::SelchangeBusList_onChange(){
Load_List_Time(pComboBox_BusList_indexes[pComboBox_BusList->GetCurSel()]);}
CTimeForm.h
#if !defined(AFX_CTIMEFORM_H__3FEEABA8_85EA_4B93_9813_A60092BB9ED8__INCLUDED_)
#define AFX_CTIMEFORM_H__3FEEABA8_85EA_4B93_9813_A60092BB9ED8__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// CTimeForm.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CTimeForm dialog
class CTimeForm : public CDialog
{
// Construction
public:
CTimeForm(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CTimeForm)
enum { IDD = TimeForm };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTimeForm)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CTimeForm)
afx_msg void timesHelp_onClick();
afx_msg void AddTime_onClick();
afx_msg void EditTime_onClick();
afx_msg void DeleteTime_onClick();
afx_msg void OK_onClick();
virtual BOOL OnInitDialog();
afx_msg void OnClose();
afx_msg void SelchangeBusList_onChange();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_CTIMEFORM_H__3FEEABA8_85EA_4B93_9813_A60092BB9ED8__INCLUDED_)
CTypeForm.cpp
#include "stdafx.h"
#include "../main.h"
#include "CTypeForm.h"
#include "../ExLibrary/CMyRecordset.h"
char* toString(int value,int radix=10);
CString IsEmpty_CEdit(CEdit* ctrl);
void sqlFilter(CString* value);
bool isUnique(CString sql,CString fields);
bool isRelate(CString sql,CString fields);
CTypeForm::CTypeForm(CWnd* pParent):CDialog(CTypeForm::IDD,pParent){
//{{AFX_DATA_INIT(CTypeForm)
//}}AFX_DATA_INIT
}
void CTypeForm::DoDataExchange(CDataExchange* pDX){
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CTypeForm)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CTypeForm, CDialog)
//{{AFX_MSG_MAP(CTypeForm)
ON_WM_CLOSE()
ON_BN_CLICKED(IDOK, OK_onClick)
ON_BN_CLICKED(Button_AddBusType, AddBusType_onClick)
ON_BN_CLICKED(Button_EditBusType, EditBusType_onClick)
ON_BN_CLICKED(Button_DeleteBusType, DeleteBusType_onClick)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/* ============================
===== User realization =====
============================ */
CListBox* pList_BusType;
CEdit* pEdit_busType;
extern CDatabase DB;
extern CMyRecordset* RS;
/* ============================
====== indexes & Funcn =====
============================ */
int* pList_BusType_indexes;
int* pLBTiLen;
void ClearIndexes_pList_BusType_indexes(){
if(pList_BusType_indexes){
delete []pList_BusType_indexes,pLBTiLen;
pList_BusType_indexes=pLBTiLen=NULL;}}
void InitIndexes_pList_BusType_indexes(int len){
pList_BusType_indexes=new int[len];
*(pLBTiLen=new int)=len;}
/* ============================
====== ............... =====
============================ */
void Load_List_BusType(){
pList_BusType->ResetContent();
RS=new CMyRecordset(&DB);
RS->Open("SELECT * FROM Type ORDER BY name","[busType_ID]&,[name]$");
RS->DefineRealCount();
ClearIndexes_pList_BusType_indexes();
if(RS->Count){
InitIndexes_pList_BusType_indexes(RS->Count);
for(int i=0;i<RS->Count;i++){
pList_BusType_indexes[i]=RS->fieldsValue[0].m_lVal;
pList_BusType->InsertString(i,RS->fieldsValue[1].m_cstring);
RS->MoveNext();}}
RS->Close();
delete RS;}
void setCurSel_TypeForm(int fictionIndex){
for(int i=0;i<*pLBTiLen;i++)
if(pList_BusType_indexes[i]==fictionIndex){
pList_BusType->SetCurSel(i);
return;}}
bool IsSelected_TypeForm(){
if(pList_BusType->GetCurSel()==-1){
AfxMessageBox("Nothing selected!");
return 0;}
return 1;}
/* ============================
====== Add Edit Remove =====
============================ */
void CTypeForm::AddBusType_onClick(){
CString newValue;
if((newValue=IsEmpty_CEdit(pEdit_busType))=="") return;
sqlFilter(&newValue);
// >>>
CString prepSql="SELECT name From Type WHERE name='$$$'";
prepSql.Replace("$$$",newValue);
if(!isUnique(prepSql,"[name]$"))return;
// >>>
CString insertSql="INSERT INTO Type (name) Values('$$$')";
insertSql.Replace("$$$",newValue);
DB.ExecuteSQL(insertSql);
Load_List_BusType();
pEdit_busType->SetWindowText("");
// :::
RS=new CMyRecordset(&DB);
CString getNewIdSql="SELECT busType_ID From Type WHERE name='$$$'";
getNewIdSql.Replace("$$$",newValue);
RS->Open(getNewIdSql,"[busType_ID]&");
RS->MoveFirst();
long newId=RS->fieldsValue[0].m_lVal;
RS->Close();
delete RS;
setCurSel_TypeForm(newId);}
void CTypeForm::EditBusType_onClick(){
if(!IsSelected_TypeForm())return;
int cID=pList_BusType_indexes[pList_BusType->GetCurSel()];
// >>>
CString newValue;
if((newValue=IsEmpty_CEdit(pEdit_busType))=="") return;
sqlFilter(&newValue);
// >>>
CString prepSql="SELECT name From Type WHERE name='$$$'";
prepSql.Replace("$$$",newValue);
if(!isUnique(prepSql,"[name]$"))return;
// >>>
CString updateSql="UPDATE Type SET Type.name = '$$1' WHERE busType_ID=$$2";
updateSql.Replace("$$1",newValue);
updateSql.Replace("$$2",toString(cID));
DB.ExecuteSQL(updateSql);
Load_List_BusType();
pEdit_busType->SetWindowText("");
// :::
setCurSel_TypeForm(cID);}
void CTypeForm::DeleteBusType_onClick(){
if(!IsSelected_TypeForm())return;
int cID=pList_BusType_indexes[pList_BusType->GetCurSel()];
// >>>
// >>>
CString relateTestSql="SELECT bus_ID FROM Bus WHERE busType_ID=$$$";
relateTestSql.Replace("$$$",toString(cID));
if(isRelate(relateTestSql,"[bus_ID]&"))return;
// >>>
CString deleteSql="DELETE * FROM Type WHERE busType_ID=";
deleteSql+=toString(cID);
DB.ExecuteSQL(deleteSql);
int oldSel=pList_BusType->GetCurSel();
Load_List_BusType();
// :::
pList_BusType->SetCurSel(oldSel>pList_BusType->GetCount()-1?pList_BusType->GetCount()-1:oldSel);}
/* ============================
=== OnInitDialog OnClose ===
============================ */
void CTypeForm::OK_onClick(){SendMessage(WM_CLOSE,0,0);}
BOOL CTypeForm::OnInitDialog(){CDialog::OnInitDialog();
// >>>
pList_BusType=(CListBox*)GetDlgItem(List_BusType);
pEdit_busType=(CEdit*)GetDlgItem(Edit_busType);
// >>>
Load_List_BusType();
return TRUE;}
void CTypeForm::OnClose(){CDialog::OnClose();
ClearIndexes_pList_BusType_indexes();}
CTypeForm.h
#if !defined(AFX_CTYPEFORM_H__7C58861A_0178_48E8_A650_7CB3A7C3C4D9__INCLUDED_)
#define AFX_CTYPEFORM_H__7C58861A_0178_48E8_A650_7CB3A7C3C4D9__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// CTypeForm.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CTypeForm dialog
class CTypeForm : public CDialog
{
// Construction
public:
CTypeForm(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CTypeForm)
enum { IDD = TypeForm };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTypeForm)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CTypeForm)
virtual BOOL OnInitDialog();
afx_msg void OnClose();
afx_msg void OK_onClick();
afx_msg void AddBusType_onClick();
afx_msg void EditBusType_onClick();
afx_msg void DeleteBusType_onClick();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_CTYPEFORM_H__7C58861A_0178_48E8_A650_7CB3A7C3C4D9__INCLUDED_)
main.cpp
#include "stdafx.h"
#include "main.h"
#include "Forms/CMainForm.h"
#include <afxdb.h>
#include "ExLibrary/CMyRecordset.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
BEGIN_MESSAGE_MAP(CApp, CWinApp)
//{{AFX_MSG_MAP(CApp)
//}}AFX_MSG
ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()
CApp::CApp(){}
BOOL CApp::InitInstance(){
AfxEnableControlContainer();
CMainForm dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
}
else if (nResponse == IDCANCEL)
{
}
return FALSE;}
CApp theApp;
CDatabase DB;
CMyRecordset* RS;
/* ============================
===== User realization =====
============================ */
char buf[10]; char* toString(int value,int radix=10){
itoa(value,buf,radix);
return buf;};
CString IsEmpty_CEdit(CEdit* ctrl){
CString newValue;
ctrl->GetWindowText(newValue);
// >>>
if(!newValue.GetLength()){
AfxMessageBox("New value can't be empty!");
return "";}
return newValue;}
void sqlFilter(CString* value){
value->Replace("'","\"");}
long isExistRecordsOnCondition(CString sql,CString fields){
RS=new CMyRecordset(&DB);
RS->Open(sql,fields);
RS->DefineRealCount();
int Count=RS->Count;
RS->Close();
delete RS;
return Count;}
bool isUnique(CString sql,CString fields){
if(isExistRecordsOnCondition(sql,fields)>0){
AfxMessageBox("New value must be unique!");
return 0;}
return 1;}
bool isRelate(CString sql,CString fields){
if(isExistRecordsOnCondition(sql,fields)>0){
AfxMessageBox("The record cannot be deleted because this record related!!");
return 1;}
return 0;}
void Load_List(CString sql,CString fields,
CListBox* ctrl,
void clearIdxFunc(void),
void initIdxFunc(int),
void setIdxFunc(int,int)){
ctrl->ResetContent();
RS=new CMyRecordset(&DB);
RS->Open(sql,fields);
RS->DefineRealCount();
clearIdxFunc();
if(RS->Count){
initIdxFunc(RS->Count);
for(int i=0;i<RS->Count;i++){
setIdxFunc(i,RS->fieldsValue[0].m_lVal);
ctrl->InsertString(i,RS->fieldsValue[1].m_cstring);
RS->MoveNext();}}
RS->Close();
delete RS;}
void Load_List(CString sql,CString fields,
CComboBox* ctrl,
void clearIdxFunc(void),
void initIdxFunc(int),
void setIdxFunc(int,int)){
ctrl->ResetContent();
RS=new CMyRecordset(&DB);
RS->Open(sql,fields);
RS->DefineRealCount();
clearIdxFunc();
if(RS->Count){
initIdxFunc(RS->Count);
for(int i=0;i<RS->Count;i++){
setIdxFunc(i,RS->fieldsValue[0].m_lVal);
ctrl->InsertString(i,RS->fieldsValue[1].m_cstring);
RS->MoveNext();}}
RS->Close();
delete RS;}
main.h
#if !defined(AFX_MAIN_H__91D8EF8A_1C83_4AD5_8267_EBB877E382FD__INCLUDED_)
#define AFX_MAIN_H__91D8EF8A_1C83_4AD5_8267_EBB877E382FD__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h"
class CApp:public CWinApp{
public:
CApp();
//{{AFX_VIRTUAL(CApp)
public:
virtual BOOL InitInstance();
//}}AFX_VIRTUAL
//{{AFX_MSG(CApp)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()};
//{{AFX_INSERT_LOCATION}}
#endif // !defined(AFX_MAIN_H__91D8EF8A_1C83_4AD5_8267_EBB877E382FD__INCLUDED_)
CMyRecordset.cpp
#include "stdafx.h"
#include "../main.h"
#include "CMyRecordset.h"
void CMyRecordset::Open(CString sql,CString fields){
for(int i=0,j=0;i<fields.GetLength();i++)
if(fields[i]==',') m_nFields++;
m_nFields++;
// >>>
fieldsValue=new CMyDBVariant[m_nFields];
fieldsNames=new CString[m_nFields];
// >>>
for(i=0;i<fields.GetLength();i++)
if(fields[i]==',') j++;
else fieldsNames[j]+=fields[i];
// >>>
((CRecordset*)this)->Open(AFX_DB_USE_DEFAULT_TYPE,sql);}
void CMyRecordset::Close(){
delete []fieldsValue;
delete []fieldsNames;}
/* =========
$ String
% Integer
& Long
# Time
========= */
void CMyRecordset::DoFieldExchange(CFieldExchange* pFX){
pFX->SetFieldType(CFieldExchange::outputColumn);
for(int i=0;i<m_nFields;i++)
switch(fieldsNames[i].GetAt(fieldsNames[i].GetLength()-1)){
case '$': RFX_Text(pFX,_T(fieldsNames[i].Left(fieldsNames[i].GetLength()-1)),fieldsValue[i].m_cstring); break;
case '&': RFX_Long(pFX,_T(fieldsNames[i].Left(fieldsNames[i].GetLength()-1)),fieldsValue[i].m_lVal); break;
case '#': RFX_Date(pFX,_T(fieldsNames[i].Left(fieldsNames[i].GetLength()-1)),fieldsValue[i].m_time); break;
case '%': break;}};
void CMyRecordset::DefineRealCount(){
Count=0;
try{
MoveLast();
while(!IsBOF()){
MovePrev();
Count++;};
MoveFirst();}
catch(CDBException *pError){
pError->Delete();}}
CMyRecordset.h
#include <afxdb.h>
/* ============================
======= CMyDBVariant =======
============================ */
class CMyDBVariant:public CDBVariant{
public:
CString m_cstring;
CTime m_time;};
/* ============================
======= CMyRecordset =======
============================ */
class CMyRecordset:public CRecordset{
virtual void DoFieldExchange(CFieldExchange*);
public:
CMyRecordset(CDatabase* pdb):CRecordset(pdb){};
long Count;
void DefineRealCount();
void Open(CString,CString);
virtual void Close();
// >>>
CMyDBVariant* fieldsValue;
CString* fieldsNames;};
6. Результат работы программы
Ниже на рисунках представлены внешние виды форм, разработанных для данного проекта.
Рисунок 2 - Основная форма приложения |
Рисунок 3 - Форма работы с автобусами |
Рисунок 4 - Форма работы с типами автобусов |
Рисунок 5 - Форма работы с временами отправлений |
Рисунок 6 - Форма работы с рейсами |
Рисунок 7 - Форма работы с маршрутами (путями) |
Рисунок 8 - Форма работы с остановками |
Рисунок 9 - Форма “О программе” |
Далее представлены предупреждения, выводимые в случаях, когда требуется ввести непустое значение, ввести уникальное значение, выбрать пункт из списка, а также предупреждение, информирующее о невозможности удаления записи в связи с присутствием связей.
Также имеются сообщения, информативного характера, не несущие в себе каких-либо ограничений.
Рисунок 10 - Сообщение в форме “Времена отправлений” |
Рисунок 11 - Сообщение о необходимости выбора |
Рисунок 12 - Сообщение о необходимости задания непустого значения |
Рисунок 13 - Сообщение о необходимости задания уникального значения |
Рисунок 14 - Сообщение о невозможности удаления связанных записей |
7. Заключение
Проделав значительную работу я изучил возможности работы с библиотекой MFC и в частности интерфейс обращения с СУБД посредством ODBC. Изучил способы манипулирования данными в элементах управления библиотеки MFC. Изучил механизмы создания пользовательских классов и принципы наследования в языке C++.
Изучил возможности обеспечения целостности данных, а также каскадного удаления данных.
8. Литература
1.
2.
3.
4.
[1] при этом считается, что один автобус может обслуживать только один рейс, но в тоже время на один рейс может приходиться несколько автобусов