Объектно-ориентированное программирование Автобусы и маршруты

Содержание

Содержание                                                                                                                              _

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 - таблица, размещающая информацию об автобусах. Содержит три поля: первое - это уникальный идентификатор автобуса, однозначно определяющий его во всем множестве других автобусов, второе - тип автобуса, третье - уникальный идентификатор рейса.

Название

тип

bus_ID

счетчик

busType_ID

длинное целое

race_ID

длинное целое

·         Path - таблица путей. Она предназначена для связи разрозненных остановочных пунктов в элементарный неделимый маршрут из одного остановочного пункта в другой. При этом направление не имеет значения. Таблица состоит из 4 полей: первое - это уникальный идентификатор пути, однозначно определяющий его во всем множестве других путей, второе и третье - уникальный идентификатор остановочного пункта, четвертое - расстояние между остановочными пунктами, выраженное во времени прохождения их из первого во второй либо из второго в первый.

Название

тип

path_ID

счетчик

start/end station_ID

длинное целое

end/start station_ID

длинное целое

time

длинное целое

·         Race - таблица, размещающая информацию о рейсах. Имеет два поля:  первое - это уникальный идентификатор рейса, однозначно определяющий его во всем множестве других рейсов, второе - описание рейса.

Название

тип

race_ID

счетчик

description

поле memo

·         Race items - таблица, организующая связь “многие ко многим” между таблицами Race и Path. Содержит два поля: первое - уникальный идентификатор рейса, второе - уникальный идентификатор пути.

Название

тип

race_ID

счетчик

path_ID

поле memo

·         Station - таблица, размещающая информацию об остановочных пунктах автобусов. Имеет два поля - это уникальный идентификатор остановочного пункта, однозначно определяющий его во всем множестве других остановочных пунктах,  и поле с его названием.

Название

тип

station_ID

длинное целое

name

длинное целое

·         Time - таблица, размещающая информацию о временах отправлений автобусов[1]. Автобусы, привязанные к одному рейсу, в течении определенного периода могут неоднократно отправляться в рейс в разные часы, что и отражается структурой данной таблицы. Таблица состоит из 3 полей: первое - это уникальный идентификатор времени, однозначно определяющий его во всем множестве других времен отправлений, второе поле - это идентификатор автобуса, свеянный с таблицей Bus (поскольку таблица Bus связанна с Time связью “один ко многим”, в Time может присутствовать несколько идентификаторов одного автобуса), третье поле - время отправления.

Название

тип

time_ID

счетчик

bus_ID

длинное целое

time

длинное целое

·         Type - таблица, размещающая информацию о типах автобусов (классов). Имеет два поля - это уникальный идентификатор типа, однозначно определяющий его во всем множестве других типов,  и поле с названием типа.

Название

тип

busType_ID

счетчик

name

поле memo

Схема данных представлена в таблице 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] при этом считается, что один автобус может обслуживать только один рейс, но в тоже время на один рейс может приходиться несколько автобусов