Программный модуль управления авиарейсами
ВВЕДЕНИЕ
В качестве средств для написания программы были
выбраны язык программирования C++/CLI и компилятор MicrosoftVisual C++ 2010.
Язык С++ является языком программирования общего
назначения. Естественная для него область применения - системное программирование,
понимаемое в широком смысле этого слова. Кроме того, С++ успешно используется
во многих областях, далеко выходящих за указанные рамки. Реализации С++ теперь
есть на всех машинах, начиная с самых скромных микрокомпьютеров - до самых
больших супер-ЭВМ, и практически для всех операционных систем.
Язык С++ был задуман для того, чтобы настоящие
программисты получили удовольствие от самого процесса программирования. За
исключением второстепенных деталей он содержит язык С как подмножество. Язык С
расширяется введением гибких и эффективных средств, предназначенных для
построения новых типов. Программист структурирует свою задачу, определив новые
типы, которые точно соответствуют понятиям предметной области задачи. Такой
метод построения программы обычно называют абстракцией данных. Информация о
типах содержится в некоторых объектах типов, определенных пользователем. С
такими объектами можно работать надежно и просто даже в тех случаях, когда их
тип нельзя установить на стадии трансляции. Программирование с использованием
таких объектов обычно называют объектно-ориентированным. Если этот метод
применяется правильно, то программы становятся короче и понятнее, а их
сопровождение упрощается.++/CLI - привязка языка программирования С++ к среде
программирования .NET фирмы Microsoft. Она интегрирует С++ стандарта ISO с
Объединённой системой типов (UnifiedTypeSystem, UTS), рассматриваемой как часть
Общей языковой инфраструктуры (CommonLanguageInfrastructure, CLI). Она
поддерживает и исходный уровень, и функциональную совместимость исполняемых
файлов, скомпилированных с родного и управляемого C++. C++/CLI представляет
собой эволюцию С++. C++/CLI стандартизирован в ECMA как ECMA-372.C++ 2010
предоставляет мощную и гибкую среду разработки, позволяющую создавать приложения
для MicrosoftWindows и приложения, основанные на Microsoft .NET. Эту среду
можно использовать в качестве интегрированной среды разработки, так и в
качестве отдельных средств.
1. ПОСТАНОВКА ЗАДАЧИ
Целью данной работы является реализация
приложения для работы с базой данных авиарейсов. Ядром любой базы данных
является модель данных. С помощью модели данных могут быть представлены объекты
предметной области и взаимосвязи между ними. Существуют три основных типа
моделей данных: иерархическая, сетевая и реляционная. В данной работе
используется иерархическая модель, которая строится по принципу иерархии типов
объектов, то есть один тип объекта является главным, а остальные, находящиеся
на низших уровнях иерархии, - подчиненными. Например, для авиарейса подчинёнными
являются дни, по которым он летает, а для дней - люди, забронировавшие места на
данный день.
В программе реализуются:
возможность добавления, редактирования и
удаления авиарейса;
возможность добавления, удаления и
редактирования записи о бронировании места на определённый день, в который
совершается рейс;
поиск авиарейсов по нескольким полям;
наглядный вывод информации на экран в виде
таблиц;
отмена последних действий.
Кроме всего вышеперечисленного в программе
реализованы дополнительные возможности. К ним относится автосохранение данных,
возможность изменения размера буфера, хранящего совершенные действия над
данными.
В данной работе для хранения информации
используются бинарные файлы. Вся работа с данными производится в оперативной
памяти, то есть чтение из файлов производится только при запуске программы,
следовательно больших затрат по времени не будет, даже если файлы довольно
большие. К тому же такой ход позволяет увеличить срок службы жесткого диска,
т.к. он используется только в начале и в конце работы с программой. Объем, же,
оперативной памяти на современных компьютерах позволяет вполне успешно
оперировать с файлами такого размера.
2. СТРУКТУРА ВХОДНЫХ И ВЫХОДНЫХ
ДАННЫХ
Внешние данные, используемые в программе,
хранятся в трёх файлах..dat - файл с информацией об авиарейсах. Состоит из
записей - полей класса flight:
int number //Номеррейсаdays[7]//
ДнинеделиDeparturePoint[50]//ПунктотправленияDestinationPoint[50]
//Пунктназначения
charDepartureTime[10]//Времяотправления[3]//Количествоместпоклассам[3]//Цена
на места по классам;// Количество списков бронирования.dat - файл с информацией
о занятых местах по дням, в которые совершаются рейсы. Состоит из записей -
полей класса reservation:[3]; // Количество занятых мест по классам[30]; //
Дата.dat - файл со списком людей, которые забронировали места. Состоит из
записей - полей класса person:name[50]; // Полноеимя; // Тип забронированного
места
Для хранения и работы с авиарейсами в программе
реализован контейнер list, а также итератор для него. Для работы со списком
объектов классов reservationи personиспользуется STL-контейнер vector.
3. ОПИСАНИЕ КЛАССОВ
.1 Классы управления данными
Шаблонный класс-контейнер list. Используется для
хранения объектов различных типов.
template<class ListType>class list
{
element<ListType> *start, *last,
*after_last; // Указатели на начало и конец спискаnumber; // Количество
элементов списка
public:<class
ListType>friendclass l_iterator;// Дружественный
класс-итератор<class
ListType>friendclass element;// Дружественный
класс-элемент
// спискаl_iterator<ListType>
iterator;
int size(); // Возвращает количество элементов
спискаpush_back (const ListType &val);// Сохранение элемента в конец
спискаpush_front (const ListType &val);// Сохранение элемента в начало
списка
// Вставка перед элементом, на который ссылается
итератор i
iterator insert (iterator i, const
ListType &val);
// Удаляет элементы из диапазона [start;end]
iterator erase (iterator start,
iterator end);
iterator erase (iterator del); // Удаляет
элемент, на который ссылается итератор delbegin(); // Возвращает итератор на
начало спискаend(); // Возвращает итератор на элемент за последнимclear();();
~list();
};
Шаблонный класс-итератор l_iterator. Является
итератором для класса-контейнера list.
template<class ListType>class
l_iterator
{<class ListType>friendclass
list;// Дружественный
класс-контейнер<class
ListType>friendclass element;// Дружественный
класс-элемент
списка
element<ListType> *cur; // Указатель на
хранимый элемент
public:();&operator*() const;// Доступ
к
элементу
списка
через
итератор
l_iterator operator++(int x);// Переход к
следующему элементу списка_iterator operator--(int x);// Переход к предыдущему
элементу списка
l_iterator operator=(l_iterator
&ptr);_iterator operator=(Object ^ ptr);==(l_iterator &ptr) { return
cur==ptr.cur ? 1: 0;}!=(l_iterator &ptr) { return cur!=ptr.cur ? 1:
0;}getNumber(); // Номер элемента по итератору
};
Шаблонный класс element. Является элементом
класса-контейнера list и служит для хранения одного объекта.
template<class ListType>class
element
{<class ListType>friendclass
list; // Дружественный класс-контейнер<class
ListType>friendclass l_iterator; // Дружественный
класс-итератор
element *prev, *next; // Указатели на предыдущий
и
// следующий элементы*val; // Указатель на объект
public:();
~element();
};
Класс-контейнерlastActionsStack.
Стек,
содержащий объекты класса lastAction. Предназначен для реализации функции
отмены последних действий. <class sType>refclass lastActionStack
{<sType> ^top; // Вершина стекаcount;//
Количество элементов в стеке
lastAction<sType> ^bottom; // Дно
стека
:Count();();
~lastActionStack();push(int opType,
int index, int dayIndex, DataGridViewRow^ Row, sType &savedObject);// Добавить
в
стек
returnElement^ pop();// Достать из
стекаreduce();// Удалить лишние элементы стека при превышении макс.
// количества
};
3.2 Классы данных
Класс flight - хранит данные об авиарейсах.
class flight
{number; // Номер
рейсаdays[7];
// Дни
неделиDeparturePoint[50];
// Пункт
отправленияDestinationPoint[50];
// Пункт
назначения
char DepartureTime[10]; // Время
отправленияclassType[3]; // Количество по классамprice[3]; // Цена на места по
классамreservNum; // Количество списков бронирования для
рейса<reservation> reserv; // Списки забронированных местна разные даты
public:
~flight();();restoreDays();// Пересборка
дней
void reducePeopleLists();// Удаление
забронированных мест на прошедшие датыfromFile(ifstream &in);// Прочитать
из файлового потокаtoFile(ofstream &out);// Записать в файловый поток
// Get- и
Set-методы<reservation>&
getReserv(); // Получить
ссылку
на
спискиgetNumber();
& СlassType(int
i);setClassType(String^ cl1, String^ cl2, String^ cl3);& Price(int
i);setPrice(String^ pr1, String^ pr2, String^
pr3);getReservNum();setReservNum(int n);setNumber(int n);& Day(int i);^
getDeparturePoint();^ getDestinationPoint();^
getDepartureTime();setDeparturePoint (String^ s);(String^ s);
void setDepartureTime (String^ s);
};
Класс reservation - хранит данные о занятых
местах по дням, в которые совершаются рейсы.
class reservation
{<person> people; // Список
людей
на
данный
рейс
int reserved[3]; // Количество занятых мест по
классам
char date[30]; // Дата
:();
~reservation();
// Get- и
Set-методы&
Reserved(int i);^ getDate();setDate (String^ s);<person>&
getPeople();fromFile(ifstream &in); // Прочитать
из
файлового
потока
void toFile(ofstream &out); // Записать в
файловый поток
};
Класс person - хранит данные человеке,
забронировавшем место.
class person
{name[50]; // Полное
имяplaceType;:();(String^
s, char t);
// Get- и
Set-методы^
getName();getPlaceType();setName(String^ s);setPlaceType (int t)
};
Статический класс
data. Хранит
объекты, используемые во всей программе в единственном экземпляре.
class data
{:list<flight> lst; // Список
авиарейсовlist<flight>::iterator
iter; // Итератор для
спискаflight
currentFlight;// Объект класса
flightautosaveInterval;// Период
автосохранения
(мин)loadFromFile();
// Загрузить
данные
из
файла
staticvoid saveToFile(); // Сохранить данные в
файл
};
3.3 Классы исключений
Класс baseException - абстрактный базовый класс
исключений.
class baseException
{:* code; // Код
ошибки*
description; // описание
ошибки:(char*
code, char* description);
virtualvoid showException() = 0; // Сообщение об
исключительной ситуации~baseException();
};
Класс fileError. Используется при возникновении
файловых ошибок.
class fileError: public
baseException
{:(char* code, char* description):
baseException(code, description);
void showException(); // Сообщение об
исключительной ситуации
};
Класс fillException. Используется,
еслинеправильно заполнены поля в некоторых формах.
class fillException: public
baseException
{:(char* code, char* description):
baseException(code, description);
void showException() // Сообщение об
исключительной ситуации
};
3.4 Структура таблиц, используемых в
программе
Таблица flightsView - список авиарейсов.
№ авиарейса.
Пункт отправления.
Пункт назначения.
Дни.
Время отправления.
(скрытый столбец) Итератор, указывающий на
данный авиарейс в контейнере list.
Таблица reservedView - список забронированныхмест.
№ п/п.
Имя.
Тип места.
4. ОПИСАНИЕ АЛГОРИТМОВ РЕШЕНИЯ
ЗАДАЧИ
Начало.
Объявление переменной idxтипа int для хранения
значения количества строк в таблице flightsView.
Объявление объекта типа EditForm^.
Запуск диалогового окна EditForm.
Если результат диалога EditForm положительный,
то переход к шагу 6,иначепереход к шагу 12.
Добавление пустой строки в таблицу flightsView.
Присвоение переменной idx значения количества
строк в таблице flightsView.
Выполнение функции
loadFromFlight(data::currentFlight,idx-1), которая загружает в последнюю строку
таблицы, заполненные в диалоге поля об авиарейсе.
Выполнение функции
data::lst.push_back(data::currentFlight), которая добавляет авиарейс в
контейнер list.
Выполнение функции UndoStack->push() -
добавления данного действия в стек последних действий.
Присвоение скрытой ячейке таблицы flightsView
итератора на последний элемент списка list.
Конец.
ФункцияSystem::Void
DeleteButton_Click(System::Object^ sender, System::EventArgs^ e) - удаление
авиарейса
Начало.
Объявление переменной idxтипа int и присвоение
ей номера текущей строки в таблице flightsView.
Присвоение статической переменной data::iter
значения итератора, указывающего на элемент в контейнере list, соответствующий
строке таблицы flightsView.
Выполнение функции UndoStack->push() -
добавления данного действия в стек последних действий.
Выполнение функции data::lst.erase(data::iter),
которая удаляет авиарейс из контейнера list.
Удаление строки из таблицы по её номеру idx.
Конец.
ЗАКЛЮЧЕНИЕ
В результате работы создана программа для
управления авиарейсами,в которой реализованы функции добавления, удаления,
изменения, поиска. Так же хочется отметить, что присутствует возможность отмены
последнего действия, поэтому в случае удаления информации её можно вернуть без
потерь.
Программный продукт выполнен в системе
MicrosoftVisual C++ 2010 с использованиеминтерфейса программирования
приложенийWindows Forms.
В качестве расширения можно реализовать более
удобный интерфейс, сортировку по полям, улучшить качество поиска.
ЛИТЕРАТУРА
1.
Шилдт Г. Полный справочник по С++. 4-е издание - Издательский дом «Вильямс»,
Москва, Санкт-Петербург, Киев, 2006 г.
.
Луцик Ю.А., Ковальчук А.М., Лукьянова И.А - Учебное пособие покурсу «Основы
алгоритмизации и программирования» - БГУИР, Минск, 2007.
.
Лафоре Р., - «Объектно-ориентированное программирование вС++» - Издательство
«Питер», Санкт-Петербург, 2011.
.
Библиотека MSDN[Электронный ресурс] /Microsoft Corp. - 2012 - Режим доступа:
#"551761.files/image001.gif">
ПРИЛОЖЕНИЕ Б
Блок-схемы алгоритмов
управление данные
таблица программа алгоритм
Функция
System::VoidUndoButton_Click(System::Object^ sender, System::EventArgs^ e) -
отмена последнего действия с рейсами
ПРИЛОЖЕНИЕ В
Скриншоты с результатами работы
ПРИЛОЖЕНИЕ Г
Листинг программы
.h
// Загрузка из объекта класса flight в строку
таблицы
private: void loadFromFlight(flight
&flt,int idx)
{>Rows[idx]->Cells[0]->Value
= flt.getNumber();>Rows[idx]->Cells[1]->Value =
flt.getDeparturePoint();>Rows[idx]->Cells[2]->Value =
flt.getDestinationPoint();<String^> ^days = gcnewarray<String^>
{"пн","вт","ср","чт","пт","сб","вс"};^
s; int count=0;(int i=0; i<7; i++)(flt.Day(i)) { if(!s) s+=days[i]; else
s+=", "+days[i]; count++;}(count==7) s="Ежедневно";>Rows[idx]->Cells[3]->Value
= s;>Rows[idx]->Cells[4]->Value = flt.getDepartureTime();
}
// Установка состояний всех кнопок в зависимости
от наличия строк в таблице
private: void setAllButtonsState()
{(!flightsView->RowCount)
{>Enabled = false;
toolStripDeleteButton->Enabled = false; >Enabled = false;>Enabled =
false; toolStripEditButton->Enabled = false;>Enabled = false;>Enabled
= false; toolStripInfoButton->Enabled = false;
}
{>Enabled = true;
toolStripDeleteButton->Enabled = true; >Enabled = true;>Enabled =
true; toolStripEditButton->Enabled = true; >Enabled = true;>Enabled =
true; toolStripInfoButton->Enabled = true;
}
}
// Поведение
главной
формы
при
запуске:
System::Void MainForm_Load(System::Object^ sender, System::EventArgs^ e)
{::loadFromFile(); // Загрузка
из
файла>timer1->Interval
= data::autosaveInterval; // Установка
периода
// автосохранения::iter
= data::lst.begin();(int i=0; i<data::lst.size(); i++)
{>Rows->Add();// Добавляем
строку
таблицы
// Добавляем итератор на последний элемент в
скрытый столбец таблицы
flightsView->Rows[i]->Cells[5]->Value
= (longlong) data::iter;
loadFromFlight(*data::iter,i); // Загружаем
информацию в строку ::iter++;
}(); // Установка состояний всех кнопок в
зависимости от
// наличия строк в таблице
}
// Кнопка "Добавить" в меню
private: System::Void
AddToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e)
{_Click(sender,e);
}
// Кнопка
"Изменить"
в
меню
: System::Void EditToolStripMenuItem_Click(System::Object^ sender,
System::EventArgs^ e)
{_Click(sender,e);
}
// Кнопка
"Удалить"
в
меню:
System::Void DeleteToolStripMenuItem_Click(System::Object^ sender,
System::EventArgs^ e)
{_Click(sender,e);
}
// Добавление
рейса:
System::Void AddButton_Click(System::Object^ sender, System::EventArgs^ e)
{^form = gcnew
EditForm();::Windows::Forms::DialogResult dr;
dr=form->ShowDialog();
// Если результат диалога положителен, то новй
рейс в data::currentFlight
if(dr==System::Windows::Forms::DialogResult::OK)
{>Enabled = true;
UndoToolStripMenuItem->Enabled = true;>Rows->Add();// Добавляем
строку
таблицыidx
= flightsView->RowCount;// Количество
строк(data::currentFlight,idx-1);
// Загружаем
строку
в
таблицу::lst.push_back(data::currentFlight);
// Добавляем
рейс
в
конец
списка
// Добавление
в
стек
отмены::flightStack->push(1,data::lst.size()-1,
-1, >Rows[idx-1],data::currentFlight);
// Добавляем итератор на последний элемент в
скрытый столбец таблицы
flightsView->Rows[idx-1]->Cells[5]->Value
= (longlong) data::lst.end()--;
setAllButtonsState(); // Установка состояний
всех кнопок в зависимости от
// наличия строк в таблице
}
}
// Изменение авиарейса
private: System::Void
EditButton_Click(System::Object^ sender, System::EventArgs^ e)
{idx =
flightsView->CurrentRow->Index;// Текущая
строка::iter
= flightsView->Rows[idx]->Cells[5]->Value; // Итератор
на
элемент,
// соотв.
строке::currentFlight
= *data::iter;^form = gcnew EditForm(true, flightsView->Rows[idx]);::Windows::Forms::DialogResult
dr;=form->ShowDialog();(dr==System::Windows::Forms::DialogResult::OK)// Если
результат
диалога
OK
{ >Enabled = true;
UndoToolStripMenuItem->Enabled = true;::currentFlight.reducePeopleLists();
// Подправляем
списки
людейloadFromFlight(data::currentFlight,idx);
// Загружаем
строку
в
таблицу
*data::iter = data::currentFlight;
// Присваиваем
редактируемому
элементу
// списка
изменённую
версию
}
}
//Удаление
авиарейса:
System::Void DeleteButton_Click(System::Object^ sender, System::EventArgs^ e)
{>Enabled = true;
UndoToolStripMenuItem->Enabled = true;idx =
flightsView->CurrentRow->Index; // Текущая
строка::iter
= flightsView->CurrentRow->Cells[5]->Value; // Итератор
на
элемент,
// соотв. строке
// Добавление в стек отмены
StaticUndoStack::flightStack->push(3,data::iter.getNumber(),
-1, >Rows[idx],*(data::iter));::lst.erase(data::iter); // Удаляем
элемент
из
списка>Rows->RemoveAt(idx);
// Удаляем
из
таблицы
setAllButtonsState();// Установка состояний всех
кнопок
// в зависимости от наличия строк в таблице
}
// Кнопка "Информация об авирейсе и
бронирование билетов"
private: System::Void
InfoButton_Click(System::Object^ sender, System::EventArgs^ e)
{::iter = flightsView->CurrentRow->Cells[5]->Value;
// Итератор
на
элемент,
// соотв.
строке
^f = gcnew ReservationForm();
f->ShowDialog();
}
// Кнопка "Выход" в меню
private: System::Void выходToolStripMenuItem_Click(System::Object^
sender, System::EventArgs^ e)
{>Close();
}
// "Сохранить"
в
меню:
System:: Void сохранитьToolStripMenuItem_Click
(System::Object^ sender, System::EventArgs^ e)
{::saveToFile();
}
// "Добавить" в панели инструментов
private: System::Void
toolStripAddButton_Click(System::Object^ sender, System::EventArgs^ e)
{_Click(sender, e);
}
// Поиск:
System::Void toolStripSearchButton_Click(System::Object^ sender,
System::EventArgs^ e)
{^ f = gcnew
SearchForm(flightsView);
f->ShowDialog();
}
// "Удалить" в панели инструментов
private: System::Void
toolStripDeleteButton_Click(System::Object^ sender, System::EventArgs^ e)
{_Click(sender,e);
}
// "Изменить" в панели инструментов
private: System::Void
toolStripEditButton_Click(System::Object^ sender, System::EventArgs^ e)
{_Click(sender,e);
}
// "Бронирование билетов и информация об
авиарейсе" в панели инструментов
private: System::Void
toolStripInfoButton_Click(System::Object^ sender, System::EventArgs^ e)
{_Click(sender,e);
}
// Отмена последних действий
private: System::Void UndoButton_Click(System::Object^
sender, System::EventArgs^ e)
{^ temp =
StaticUndoStack::flightStack->pop();
if(temp->opType == 1) // Если отмена
добавления
flightsView->Rows->RemoveAt(temp->index);
else// Если отмена удаления или изменения
{(temp->opType == 3) // Если отмена удаления
flightsView->Rows->Insert(temp->index,1);
// Вставляем
пустую
строку(int
i=0; i < temp->Row->Cells->Count;
i++)>Rows[temp->index]->Cells[i]->Value =
>Row->Cells[i]->Value; // Копируем
содержимое
строки
}(!StaticUndoStack::flightStack->Count())
{ UndoButton->Enabled = false; UndoToolStripMenuItem->Enabled = false;}
setAllButtonsState(); // Установка состояний
всех кнопок в зависимости от // наличия строк в таблице
}
// Действия
при
закрытии
формы:
System::Void MainForm_FormClosed(System::Object^ sender,
System::Windows::Forms::FormClosedEventArgs^ e)
{::saveToFile();
}
// Кнопка отмены в меню
private: System::Void
UndoToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e)
{_Click(sender,e);
}
// Автосохранение:
System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e)
{::saveToFile();
}
// Кнопка "О программе" в панели
инструментов
private: System::Void
toolStripAbout_Click(System::Object^ sender, System::EventArgs^ e)
{^form = gcnew About;>ShowDialog();
}
// Кнопка
"О
программе"
в
меню:
System::Void AboutToolStripMenuItem_Click(System::Object^ sender,
System::EventArgs^ e)
{^form = gcnew
About;>ShowDialog();
}
// Кнопка
"Настройки"
в
меню:
System::Void SettingsToolStripMenuItem_Click(System::Object^ sender,
System::EventArgs^ e)
{^form = gcnew Settings(timer1);
form->ShowDialog();
}.h
// Загрузка из списка забронированных мест в
таблицу
private: void loadFromPeople()
{>Rows->Clear(); // Очищаем
таблицу
// Количество
человек
на
данную
датуsize
=
(*data::iter).getReserv()[listBox1->SelectedIndex].getPeople().size();(!size)
{>Enabled = false;
EditButton->Enabled = false;;
}{ DeleteButton->Enabled = true;
EditButton->Enabled = true; }(int i=0; i<size; i++)
{>Rows->Add();// Добавляем
строку
таблицы>Rows[i]->Cells[0]->Value
= i+1;// Номер с
единицы
// Заполняем
ячейки
таблицы>Rows[i]->Cells[1]->Value
=(*data::iter).getReserv()
[listBox1->SelectedIndex].getPeople()[i].getName();>Rows[i]->Cells[2]->Value
= (*data::iter).getReserv()
[listBox1->SelectedIndex].getPeople()[i].getPlaceType()
+ " класс";
}
}
// Установка
состояния
клавиши
"Добавить":
void setAddReservedButtonState()
{((comboBox1->SelectedIndex==0
&& (*data::iter).getReserv()[listBox1->SelectedIndex].Reserved(0)
>= (*data::iter).СlassType(0))
|| (comboBox1->SelectedIndex==1
&& (*data::iter).getReserv()[listBox1->SelectedIndex].Reserved(1)
>= (*data::iter).СlassType(1))
|| (comboBox1->SelectedIndex==2
&& (*data::iter).getReserv()[listBox1->SelectedIndex].Reserved(2)
>= (*data::iter).СlassType(2)))
{AddReservedButton->Enabled =
false; }{AddReservedButton->Enabled = true; }
}
// Установка количества свободных мест на форме
private: void UpdateFreeLabels(int
SelectedItem)
{free = (*data::iter).СlassType(0)
-// Кол-во
свободных
мест
(*data::iter).getReserv()[SelectedItem].Reserved(0);->Text
= Convert::ToString(free);// Обновление
на
форме=
(*data::iter).СlassType(1) -
(*data::iter).getReserv()[SelectedItem].Reserved(1);->Text
= Convert::ToString(free);= (*data::iter).СlassType(2)
-
(*data::iter).getReserv()[SelectedItem].Reserved(2);->Text
= Convert::ToString(free);
}
// Поведение
формы
при
загрузке:
System::Void ReservationForm_Load(System::Object^ sender, System::EventArgs^ e)
{
(*data::iter).restoreDays(); // Добавляем/Удаляем
необходимые
дни>Text
= "Рейс
№ " + (*data::iter).getNumber() + ". Информация
и
бронирование
мест";(int
i=0; i<(*data::iter).getReserv().size();
i++)->Items->Add((*data::iter).getReserv()[i].getDate());
// Заполнение на форме информации о местах
label4->Text =
Convert::ToString((*data::iter).СlassType(0));->Text
= Convert::ToString((*data::iter).Price(0));->Text =
Convert::ToString((*data::iter).СlassType(1));->Text
= Convert::ToString((*data::iter).Price(1));->Text =
Convert::ToString((*data::iter).СlassType(2));->Text
= Convert::ToString((*data::iter).Price(2));->SelectedIndex =
0;->SelectedIndex = 0;
}
// Добавление
человека:System::Void
AddReservedButton_Click(System::Object^sender,System::EventArgs^e)
{{(textBox1->Text=="")
throw fillException("4","Введите
имя!");
// Установка
состояний
конопок>Enabled
= true; DeleteButton->Enabled = true; >Enabled =
true;>Rows->Add();// Добавляем
строку
таблицы
int idx = reservedView->RowCount-1; // Индекс
последней добавленной строки
// Установка номеров по порядку(idx == 0)
reservedView->Rows[idx]->Cells[0]->Value = 1;
else
reservedView->Rows[idx]->Cells[0]->Value =
((int)
reservedView->Rows[idx-1]->Cells[0]->Value)+1;
// Заполнение
строки
таблицы
значениями
TextBox’ов>Rows[idx]->Cells[1]->Value
= textBox1->Text;>Rows[idx]->Cells[2]->Value =
->SelectedItem->ToString();classN =
(char)comboBox1->SelectedIndex+1;//Выбранный
тип
места
// Добавление
в
вектор
(*data::iter).getReserv()[listBox1->SelectedIndex].().push_back(person(textBox1->Text,classN));
(*data::iter).getReserv()[listBox1->SelectedIndex].(comboBox1->SelectedIndex)++;<person>::iterator
itr =
(*data::iter).getReserv()[listBox1->SelectedIndex].getPeople().end()
- 1;
// Добавление
в
стек
отмены::personStack->push
(1, idx, listBox1->SelectedIndex, >Rows[idx], *itr);
// Установка
текущей
строки>CurrentCell
= reservedView->Rows[idx]->Cells[0]; _SelectionChanged(sender,e);// Обработка
изменения
текущей
// строки();// Состояние клавиши «Добавить»(listBox1->SelectedIndex);
// Обновляем количество
// свободных мест
} catch(baseException &e)
{e.showException();}
}
// Изменение
выделения
даты:
System::Void listBox1_SelectedIndexChanged(System::Object^ sender,
System::EventArgs^ e)
{(listBox1->SelectedIndex);// Обновление
информации
о
// свободных местах();// Загрузка списка в
таблицу ();// Состояние клавиши «Добавить»_SelectionChanged(sender,e);//
Обработка изменения выделения
StaticUndoStack::personStack->~lastActionStack();
// Очистка
стека>Enabled
= false;// Отключение отмены
}
// Выделение
новой
строки
в
таблице:
System::Void reservedView_SelectionChanged(System::Object^ sender,
System::EventArgs^ e)
{(!reservedView->RowCount)
return;// Если таблица
пуста(Convert::ToString(reservedView->Rows[0]->Cells[1]->Value)=="")
return;idx = reservedView->CurrentRow->Index; // Текущая
строка
// Заполнение textBox’а и comboBox’а именем и
типом места
textBox1->Text =
Convert::ToString(reservedView->Rows[idx]->Cells[1]->Value);classN =
Convert::ToString(reservedView->Rows[idx]->Cells[2]->Value)[0];
comboBox1->SelectedIndex = classN - 49;
}
private: System::Void
DeleteButton_Click(System::Object^ sender, System::EventArgs^ e)
{i =
reservedView->CurrentRow->Index;prevType =
(*data::iter).getReserv()[listBox1->SelectedIndex].
getPeople()[i].getPlaceType();
//i - номер удаляемого человека (если считать с
1)
i =
Convert::ToInt32(reservedView->Rows[i]->Cells[0]->Value);<person>::iterator
itr = (*data::iter).// Итератор
на
удалемого
человека()[listBox1->SelectedIndex].getPeople().begin()
+ i-1;
// Добавление
в
стек
отмены::personStack->push
(3, i-1, listBox1->SelectedIndex, >CurrentRow, *(itr));
(*data::iter).getReserv()[listBox1->SelectedIndex].Reserved(prevType-1)--;(listBox1->SelectedIndex);
// Обновляем
количество
свободных
мест
// Удаляем
из
таблицы
и
вектора>Rows->RemoveAt(reservedView->CurrentRow->Index);
(*data::iter).getReserv()[listBox1->SelectedIndex].getPeople().erase(itr);
// Установка состояний кнопок в зависимости от
наличия строк в таблице
if(!reservedView->RowCount)
{DeleteButton->Enabled = false;
EditButton->Enabled = false;}(i=0; i<reservedView->RowCount;
i++)>Rows[i]->Cells[0]->Value = i+1;();>Enabled = true;
}
// Изменение
информации
о
человеке:
System::Void EditButton_Click(System::Object^ sender, System::EventArgs^ e)
{{(textBox1->Text=="")
throw fillException("4","Необходимо
ввести
имя
пассажира!");//
Если
поле
имени
пустоidx
= reservedView->CurrentRow->Index;// Номер
текущей
строкиprevType
=
(*data::iter).getReserv()[listBox1->SelectedIndex].getPeople()[idx].getPlaceType();//
Тип
места
до
изменения((prevType-1)!=comboBox1->SelectedIndex)
// Если
не
совпадают
типы
мест
{// до
изменеия
и
после
(*data::iter).getReserv()[listBox1->SelectedIndex].(prevType-1)--;
(*data::iter).getReserv()[listBox1->SelectedIndex].
Reserved(comboBox1->SelectedIndex)++;
}// Если содержимое полей не изменено, то выход
из функции
if(Convert::ToString(reservedView->Rows[idx]->Cells[1]->Value)
==
textBox1->Text) ;
// Итератор на начало вектора забронированных
мест
vector<person>::iterator itr =
(*data::iter).getReserv()
[listBox1->SelectedIndex].getPeople().begin();
// Добавление
в
стек
отмены::personStack->push
(2, idx, listBox1->SelectedIndex, reservedView->Rows[idx], *(itr+idx));
// Изменение
ячеек
в
таблице>Rows[idx]->Cells[1]->Value
= textBox1->Text;>Rows[idx]->Cells[2]->Value =
comboBox1->SelectedItem->ToString();classN =
(int)comboBox1->SelectedIndex+1;// Тип
выбранного
места
// Изменение
в
элементе
вектора
(*data::iter).getReserv()[listBox1->SelectedIndex].getPeople()[idx].setName(textBox1->Text);
(*data::iter).getReserv()[listBox1->SelectedIndex].getPeople()[idx].setPlaceType(classN);(listBox1->SelectedIndex);//
Установка
свободных
мест
// Установка
состояний
кнопок();>Enabled
= true;
} catch(baseException &e) {
e.showException(); }
}
// Изменение типа места в выпадающем списке
private: System::Void
comboBox1_SelectedIndexChanged(System::Object^ sender, System::EventArgs^ e)
{
// Если список забронированных мест не пуст
if((*data::iter).getReserv()[listBox1->SelectedIndex].getPeople().size())
{
//prevType - предыдущий
тип
местаprevType
=
(*data::iter).getReserv()[listBox1->SelectedIndex].getPeople()[reservedView->CurrentRow->Index].getPlaceType();
// Если мест выбранного типа не осталось
if((*data::iter).getReserv()[listBox1->SelectedIndex].Reserved(comboBox1->SelectedIndex)
== (*data::iter).СlassType(comboBox1->SelectedIndex))->SelectedIndex
= prevType-1;// Устанавливаем
предыдущий
тип
}();// Установка состояния кнопки «Добавить»
}
// Отмена
последнего
действия:
System::Void UndoButton_Click(System::Object^ sender, System::EventArgs^ e)
{// Извлечение
элемента
из
стека^
temp = StaticUndoStack::personStack->pop();
if(temp->opType == 1) // Если отмена добавления
reservedView->Rows->RemoveAt(temp->index);
else// Если отмена удаления или изменения
{(temp->opType == 3) // Если отмена удаления
{// Вставляем
пустую
строку>Rows->Insert(temp->index,1);
(int i=0; i<reservedView->RowCount; i++) // Перенумеровка>Rows[i]->Cells[0]->Value
= i+1;
}// Если
отмена
изменения
{prevType =
Convert::ToString(reservedView->Rows[temp->index]->Cells[2]->Value)[0]
- 49;newType = Convert::ToString(temp->Row->Cells[2]->Value)[0] - 49;
if(prevType!=newType)// Если прердыдущий тип
места не равен новому
{
(*data::iter).getReserv()[listBox1->SelectedIndex].Reserved(prevType)--;
(*data::iter).getReserv()[listBox1->SelectedIndex].Reserved(newType)++;
}
}(int i=0; i <
temp->Row->Cells->Count; i++)>Rows[temp->index]->Cells[i]->Value
= temp->Row->Cells[i]->Value; // Копируем
содержимое
строки
}();// Установка состояния кнопки
«Добавить»(listBox1->SelectedIndex); // Обновляем количество свободных мест
// Установка состояний кнопок «Отменить» и
«Удалить»
if
(!StaticUndoStack::personStack->Count()) >Enabled = false;
(!reservedView->RowCount)
{ DeleteButton->Enabled = false;
EditButton->Enabled = false; }{ DeleteButton->Enabled = true;
EditButton->Enabled = true; }
}
// Отмена
через
Ctrl+Z: System::Void ReservationForm_KeyDown(System::Object^ sender,
System::Windows::Forms::KeyEventArgs^ e)
{>Handled =
true;(e->KeyData==(Keys::Control | Keys::Z) && StaticUndoStack::
personStack->Count())_Click(sender,e);
}.h
// Поиск:
System::Void FindButton_Click(System::Object^ sender, System::EventArgs^ e)
{flag;>Rows->Clear();// Очищаем
таблицу(textBox1->Text==""&&
textBox2->Text==""&&
textBox3->Text==""&&
!checkedListBox1->CheckedItems->Count)// Если
условия
поиска
не
заданы;(int
i=0; i<dataGridMain->RowCount; i++)
{=0;((textBox1->Text==""
|| Convert::ToInt32(dataGridMain->Rows[i]->Cells[0]->Value) ==
Convert::ToInt32(textBox1->Text)) &&
((Convert::ToString(dataGridMain->Rows[i]->Cells[1]->Value) ==
textBox2->Text) || textBox2->Text=="") &&
((Convert::ToString(dataGridMain->Rows[i]->Cells[2]->Value) ==
textBox3->Text)|| textBox3->Text==""))// Если
заполнено
хотя
бы
одно
из
полей
и
элемент
найден
{(int j=0;
j<checkedListBox1->Items->Count; j++)
{// Итератор на элемент, соотв. строке::iter =
dataGridMain->Rows[i]->Cells[5]->Value;// Если рейс не летает по
выбранным дням
if(checkedListBox1->GetItemCheckState(j)
== CheckState::Checked && !(*data::iter).Day(j))
{ flag = 1; break; } // Флаг несовпадения дней
}
// Если дни не выбраны или выбранные дни
совпадают
if(!checkedListBox1->CheckedItems->Count
|| flag==0)
{<Object^> ^rowData =
gcnewarray<Object^>(dataGridMain->Rows[i]->Cells->Count);// Копируем
строку
из
основной
таблицы(int
j=0; j<rowData->Length; j++)rowData[j] =
dataGridMain->Rows[i]->Cells[j]->Value;>Rows->Add(rowData);// Добавляем
строку
}
}
}
}
// Контроль на ввод только цифр в номер рейса
private: System::Void
textBox1_KeyPress(System::Object^ sender,
System::Windows::Forms::KeyPressEventArgs^ e)
{(e->KeyChar >= '0'&&
e->KeyChar <= '9' || e->KeyChar==8)>Handled = false;e->Handled =
true;
}
// Двойной
щелчок
на
строке
таблицы:
System::Void foundFlightsView_CellDoubleClick(System::Object^ sender,
System::Windows::Forms::DataGridViewCellEventArgs^ e)
{::iter =
foundFlightsView->CurrentRow->Cells[5]->Value; // Итератор
на
// элемент,
соотв.
строке
^f = gcnew ReservationForm();>ShowDialog();
}.h
// Нажатие кнопки «Отмена»
private: System::Void
CancelButton_Click(System::Object^ sender, System::EventArgs^ e)
{>Close();
}
// Нажатие
кнопки
«OK»: System::Void OkButton_Click(System::Object^ sender, System::EventArgs^ e)
{
// Изменение
максимального
количества
отменяемых
действий::MaxActionsNum
= (int)numericUpDown1->Value;
StaticUndoStack::flightStack->reduce(); //
Изменение размера стека при // необходимости
timer1->Interval =
(int)numericUpDown2->Value*60000; // Изменяем
интервал
таймера
// в
главной
форме::autosaveInterval
= (int) timer1->Interval;// Период
автосохранения>Close();
}
// Загрузка
формы
«Настройки»:
System::Void Settings_Load(System::Object^ sender, System::EventArgs^ e)
{->Value =
StaticUndoStack::MaxActionsNum;// Максимальное
количество
// отменяемых
действий->Value
= timer1->Interval/60000;// Период
автосохранения
}.h
// Загрузка формы добавления/редактирования
private: System::Void
EditForm_Load(System::Object^ sender, System::EventArgs^ e)
{
// Если в вызывающей форме нажата кнопка
"Изменить", а не добавить
if(editingMode)
{
// Заполняем
TextBox'ы->Text
= Convert::ToString(data::currentFlight.getNumber());->Text =
data::currentFlight.getDeparturePoint();->Text =
data::currentFlight.getDestinationPoint();->Text =
Convert::ToString(data::currentFlight.СlassType(0));->Text
= Convert::ToString(data::currentFlight.Price(0));->Text =
Convert::ToString(data::currentFlight.СlassType(1));->Text
= Convert::ToString(data::currentFlight.Price(1));->Text =
Convert::ToString(data::currentFlight.СlassType(2));->Text
= Convert::ToString(data::currentFlight.Price(2));
// Устанавливаем
дни
недели(int
i=0; i<checkedListBox1->Items->Count;
i++)->SetItemCheckState(i,(CheckState)data::currentFlight.Day(i));
// Устанавливаем время отправления->Value =
DateTime::Parse(data::currentFlight.getDepartureTime());
}
}
// Проверка ввода только цифр в TextBox'ы
private: void
numberOnlyControl(System::Windows::Forms::KeyPressEventArgs^ e)
{(e->KeyChar >= '0'&&
e->KeyChar <= '9' || e->KeyChar==8)>Handled = false;e->Handled =
true;
}
// Проверка
на
дубликаты
рейсов:
bool checkCopy(int number)
{<flight>::iterator
iterator;(iterator = data::lst.begin(); iterator!=data::lst.end(); iterator++)
{// Если
указан
уже
существующий
рейс((number==(*iterator).getNumber()
&& !editingMode) || (number==(*iterator).getNumber() &&
(*data::iter).getNumber()!=number && editingMode));
};
}
// Нажатие
ОК:
System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{{(editingMode) // Если режим редактирования
StaticUndoStack::flightStack->push(2,data::iter.getNumber(),-1,Row,data::currentFlight);//
Добавляем
в
стек
отмены(int
i=1; i<10; i++)// Проверяем
заполненность
textBox’ов
{^ t =
(TextBox^)this->Controls["textBox"+i.ToString()];
if(t->Text=="") throw
fillException("2","Необходимо заполнить все поля!");
}
// Если рейс уже существует и/или не выбраны дни
if(checkCopy(Convert::ToInt32(textBox1->Text)))
throw fillException("4","Данный
рейс
уже
существует");(checkedListBox1->CheckedItems->Count==0)
throw fillException("3","Выберите
дни,
по
которым
совершается
рейс!");//
Добавляем
в
текущий
рейс
информацию
из
полей
формы::currentFlight.setNumber(Convert::ToInt32(textBox1->Text));
::currentFlight.setDeparturePoint(textBox2->Text);::currentFlight.setDestinationPoint(textBox3->Text);::currentFlight.setClassType(textBox4->Text,
textBox6->Text, textBox8->Text);::currentFlight.setPrice(textBox5->Text,
textBox7->Text, textBox9->Text);
// Копируем
время
отправления::currentFlight.setDepartureTime(dateTimePicker1->Value.ToShortTimeString());
// Устанавливаем
выбранные
дни
недели(int
i=0; i<checkedListBox1->Items->Count; i++)
{((int)checkedListBox1->GetItemCheckState(i))
::currentFlight.Day(i)=1;data::currentFlight.Day(i)=0;
}>DialogResult=System::Windows::Forms::DialogResult::OK;>Close();
}(baseException &e)
{ e.showException();}
}.h<class ListType>class
list;<class ListType>class element;<class ListType>class
l_iterator;
// Шаблон
класса
"Список"<class
ListType>class list
{<ListType> *start, *last, *after_last; //
Указатели на начало и конец спискаnumber;// Количество элементов списка
public:<class
ListType>friendclass l_iterator;<class ListType>friendclass
element;l_iterator<ListType> iterator;
int size() { return number; }// Возвращает
количество элементов спискаpush_back (const ListType &val); // Сохранение
элемента в конец спискаpush_front (const ListType &val); // Сохранение
элемента в начало списка
iterator insert (iterator i, const
ListType &val); // Вставка
перед
элементом,
на
// который
ссылается
итератор
ierase (iterator start, iterator end); // Удаляет
элементы
из
диапазона
// [start;end]erase (iterator
del);// Удаляет
элемент,
на
который
// ссылается итератор delbegin() // Возвращает
итератор на начало
// списка
{iterator p;(start)
p.cur=start;p.cur = after_last;p;
} end() {iterator p;
p.cur=after_last; return p;} // Возвращает
итератор
на
// элемент списка, следующий за последнимclear()
{while(start) {last=start->next;
delete[] start; start=last;}=last=0; number=0;_last=new
element<ListType>[1];_last->next=0;
}() { start=0; last=0;
number=0;_last=new element<ListType>[1];
after_last->next=0;} // Инициализируем список
// Удаляем весь список
~list() {while(start) {
last=start->next; delete[] start; start=last;} }
};
// Шаблон
элемента
списка<class
ListType>class element
{<class ListType>friendclass
list;<class ListType>friendclass l_iterator;*prev, *next;*val;:()
{val=new ListType;}
~element() {delete val;}
};
// Шаблон
итератора
списка<class
ListType>class l_iterator
{<class ListType>friendclass
list;<class ListType>friendclass element;<ListType> *cur;:() {returnreinterpret_cast<longlong>(cur);}&operator*()
const { return *cur->val; } // Доступ
к
элементу
списка
// через
итератор_iterator
operator++(int x){ cur==0 ? cur: cur=cur->next; return *this; }_iterator
operator--(int x) { cur==0 ? cur: cur=cur->prev; return *this; }_iterator
operator=(l_iterator &ptr) { cur=ptr.cur; return *this;}_iterator
operator=(Object ^ ptr) { longlong tmp =
Convert::ToInt64(ptr);cur=reinterpret_cast<element<ListType>
*>(tmp); return *this;}==(l_iterator &ptr) { return cur==ptr.cur ? 1:
0;}!=(l_iterator &ptr) { return cur!=ptr.cur ? 1: 0;}getNumber()
{num = 0;<ListType> *temp =
cur;(temp->prev!=0)
{= temp->prev;
num++;
}num;
}
};
// Вставка элемента в конец списка
template<class
ListType>list<ListType>::push_back(const ListType &val)
{(!last) // Если список пуст
{
last = new
element<ListType>[1]; // Создаём
новый
элемент
списка=last;>prev=0;
}
{>next= new
element<ListType>[1]; // Создаём
новый
элемент
списка
// Связываем элемент с
остальными>next->prev=last;
last=last->next;
}>next=after_last;_last->prev=last;
*last->val=val; // Заполняем
элемент
number++;// Увеличиваем счётчик элементов списка
}
// Вставка элемента в начало списка<class
ListType>
void
list<ListType>::push_front(const ListType &val)
{(!start) // Если список пуст
{
last = new
element<ListType>[1]; // Создаём
новый
элемент
списка
start=last;
// Связываем элемент с остальными
last->next=after_last;_last->prev=last;
}
{>prev= new
element<ListType>[1]; // Создаём
новый
элемент
списка
// Связываем элемент с остальными>prev->next=start;
start=start->prev;
}>prev=0;
*start->val=val; // Заполняем элемент++;//
Увеличиваем счётчик элементов списка
}
// Вставка элемента перед элементом, на который
указывает iterator i
template<class
ListType>_iterator<ListType> list<ListType>::insert(iterator i,
const ListType &val)
{(!i.cur) return i;<ListType>
*n;(i.cur==after_last && !start) // Если
список
пуст
{= new element<ListType>[1];
// Создаём
новый
элемент
списка
start=last;
// Связываем элемент с остальными
last->next=after_last;_last->prev=last;>prev=0;
}
{(i.cur==after_last) // Если
итератор
указывает
на
элемент
после
// последнего
{>next= new
element<ListType>[1]; // Создаём
новый
элемент
списка
// Связываем элемент с
остальными>next->prev=last;
last=last->next;>next=after_last;_last->prev=last;
}
{
n = new element<ListType>[1];
// Связываем элемент с остальными
n->next=i.cur;>prev=i.cur->prev;.cur->prev=n;(n->prev)
n->prev->next=n;start = n;
}
}
*i.cur->prev->val=val; // Заполняем
элемент
number++;// Увеличиваем счётчик элементов
спискаtemp;
temp.cur=i.cur->prev;
return temp;
}
// Удаление элементов в диапазоне [start,end]
template<class
ListType>_iterator<ListType> list<ListType>::erase(iterator
start, iterator end)
{(!start.cur) return end;(!end.cur)
return start;
element<ListType> *temp,
*t_end,// Элемент после удаляемой
последовательности
*t_start=start.cur->prev; // Элемент перед
удаляемой последовательностью
end.cur==after_last ?
t_end=after_last: t_end=end.cur->next;
while(start.cur!=t_end)// Удаление элементов в
диапазоне
{= start.cur->next; [] start.cur;
.cur = temp;-;
} (!t_start &&
t_end==after_last) // Если границы
- начало
и
конец
списка<ListType>::start=last=0;
{
if(!t_start)// Если первая граница - начало
списка
{<ListType>::start=t_end;<ListType>::start->prev=0;
}(t_end==after_last)// Если
вторая
граница
- конец
списка
{=t_start;>next=after_last;
}
}tmp;.cur=t_end;
return tmp;
}
// Удаление элемента, на который указывает
итератор del
template<class
ListType>_iterator<ListType> list<ListType>::erase(iterator del)
{<ListType> *temp;(!start)
return del;(del.cur == after_last) return del;// Если
удаляемый
элемент
после
последнего
if(del.cur == start && number==1)// Если
удаляемый элемент в начале списка и единственный
{[] del.cur;= 0; last =
0;_last->prev = 0;
}
{(del.cur == start)// Если
удаляемый
элемент
в
начале
списка
{= del.cur->next;[]
del.cur;>prev = 0;= start;
}(del.cur == last)// Если
удаляемый
элемент
в
конце
списка
{= del.cur->prev;[]
del.cur;>next = after_last;= last;
}// В общем случае
{= del.cur->next;
del.cur->next->prev =
del.cur->prev;.cur->prev->next = del.cur->next;[] del.cur;
}
}-;tmp;.cur = temp;tmp;
}.hbaseException
{:* code; // Код
ошибки*
description; // Описание
ошибки:(char*
code, char* description)
{>code = newchar[strlen(code)+1];
strcpy(this->code, code);>description = newchar[strlen(description)+1];
(this->description, description);
}showException() = 0; // Сообщение
об
исключительной
ситуации~baseException()
{delete code; delete description;}
};
// Ошибки
при
работе
с
файламиfileError:
public baseException
{:(char* code, char* description):
baseException(code, description) {}
void showException() // Сообщение об
исключительной ситуации
{ MessageBox::Show(gcnew
String(description), "Файловая
ошибка.
Код
" + gcnew String(code), MessageBoxButtons::OK, MessageBoxIcon::Error); }
};
// Ошибки при заполнении полей в формах
class fillException: public
baseException
{:(char* code, char* description):
baseException(code, description) {}
void showException() // Сообщение об
исключительной ситуации
{ MessageBox::Show(gcnew
String(description),"Ошибка
заполнения.
Код
" + gcnew String(code),MessageBoxButtons::OK, MessageBoxIcon::Warning);}
};.h<class sType>refclass
lastAction;<class sType>refclass
lastActionStack;returnElement;StaticUndoStack;
// Описание
последнего
действия<class
sType>refclass lastAction
{
public:opType;// Тип операции (1 - добавление,
2- изменение, 3 - удаление)index;// Индекс в спискеdayIndex;// Индекс
выбранного дня^ Row; // Строка из таблицы (для отмены удаления и изменения)^
prev;// Ссылка на предыдущее действие^ next;// Ссылка на следующее действие
sType *savedObject;// Сохранённый
рейс(int
opType, int index, int dayIndex, DataGridViewRow^ Row, sType &savedObject);
~lastAction() {delete savedObject;}
};
// Стек
последних
действий<class
sType>refclass lastActionStack
{
lastAction<sType> ^top; // Вершина
стекаcount;// Количество элементов в стеке
lastAction<sType> ^bottom; // Дно
стека
:Count() {return count;}() { count=0; }
~lastActionStack()
{ while(count)
{ if(count!=1) { top=top->prev;
delete top->next; }top;-;
}
}push(int opType, int index, int
dayIndex, DataGridViewRow^ Row, sType &savedObject);
returnElement^ pop();reduce();// Удалить лишние
элементы стека при превышении макс. количества
};
// Элемент, возвращаемый стеком при отмене
последнего действия
refclass returnElement
{:(int opType, int index, int
dayIndex, DataGridViewRow^ Row)
{>opType = opType;>Row = Row;
>index = index;>dayIndex = dayIndex;
}opType;index;dayIndex;
DataGridViewRow^ Row;
};
// Класс со стеком последних действий
refclass StaticUndoStack
{:lastActionStack<flight>^
flightStack = gcnew
lastActionStack<flight>;lastActionStack<person>^ personStack =
gcnew lastActionStack<person>;
staticint MaxActionsNum = 1;
};
// Конструктор для последнего действия
template<class
sType><sType>::lastAction(int opType, int index, int dayIndex,
DataGridViewRow^ Row, sType &savedObject)
{ (opType!=1) // Если удаление или изменение
{>Row =(DataGridViewRow^)
Row->Clone(); // Копируем
строку(int
i=0;i<Row->Cells->Count;i++)>Row->Cells[i]->Value =
Row->Cells[i]->Value;
}>opType = opType; this->index
= index; this->dayIndex = dayIndex;>savedObject = new sType(savedObject);
}
// Добавление в стек последнего
действия<class sType>
void
lastActionStack<sType>::push(int opType, int index, int dayIndex,
DataGridViewRow^ Row, sType &savedObject)
{(count ==
StaticUndoStack::MaxActionsNum) // если
достигнуто
макс.
количество
{ (count==1) delete bottom;
{= bottom->next; // Обновляем
дно
стекаbottom->prev;
}-;
} <sType>^ New = gcnew lastAction<sType>(opType,
index, dayIndex, Row, savedObject);(count!=0)
{>prev = top;// Обновляем
ссылку
на
предыдущий
элемент
New->prev->next = New; // Обновляем ссылку
на следующий элемент
// предыдущего
}bottom = New;// Запоминаем дно стека= New;//
Обновляем вершину стека++;
}
// Извлечение рейса из стека последнего действия
template<>inline^
lastActionStack<flight>::pop()
{^ bufRow;^ buf;(!top) return
buf;<flight>::iterator l_iter = data::lst.begin(); // Итератор
в
списке
авиарейсов(int
i=0; i<top->index; i++)
l_iter++; // Устанавливаем итератор на требуемый
индекс(top->opType == 1) // Отмена добавления::lst.erase(l_iter); // Удаляем
добавленный рейс в списке lst// Отмена удаления или изменения
{
bufRow =
(DataGridViewRow^)top->Row->Clone();// Копия
строки(int
i=0; i < top->Row->Cells->Count; i++)
// Копируем
содержимое
строки>Cells[i]->Value
= top->Row->Cells[i]->Value;
if(top->opType == 3) // Отмена удаления
// Вставляем сохранённый рейс в списке lst
l_iter = data::lst.insert(l_iter,
*(top->savedObject));
else// Если отмена изменения
*l_iter = *(top->savedObject); //
Восстанавливаем объект в списке lst
// Обновляем итератор в скрытом
столбце>Cells[5]->Value = (longlong) l_iter;
}
// Элемент
для
возврата=
gcnew returnElement(top->opType, top->index, top->dayIndex, bufRow);
<flight>^ old;= top;
top = top->prev; // Изменение вершины
стекаold;// Удаление старой вершины-;// Уменьшение количества элементов в
стекеbuf;
}
// Извлечение забронированного места из стека
последнего действия
template<>inline^
lastActionStack<person>::pop()
{^ bufRow;^ buf;(!top) return
buf;placeType = top->savedObject->getPlaceType() - 1;// Тип
забронированного
места<person>::iterator
v_iter = (*data::iter).getReserv()[top->dayIndex].getPeople().begin() +
top->index;
if(top->opType == 1) // Отмена добавления
{
(*data::iter).getReserv()[top->dayIndex].getPeople().erase(v_iter);
(*data::iter).getReserv()[top->dayIndex].Reserved(placeType)--;
}// Отмена удаления или изменения
{
bufRow =
(DataGridViewRow^)top->Row->Clone();// Копия
строки(int
i=0; i < top->Row->Cells->Count; i++)
// Копируем
содержимое
строки>Cells[i]->Value
= top->Row->Cells[i]->Value;(top->opType == 3) // Отмена
удаления
{_iter =
(*data::iter).getReserv()[top->dayIndex].getPeople().insert(v_iter,
*(top->savedObject)); // Вставляем
сохранённую
(*data::iter).getReserv()[top->dayIndex].Reserved(placeType)++;
}// Если отмена изменения
*v_iter = *(top->savedObject); //
Восстанавливаем объект в векторе
// reserv
}
// Элемент
для
возврата=
gcnew returnElement(top->opType, top->index, top->dayIndex, bufRow);
<person>^ old;= top;
top = top->prev; // Изменение вершины
стекаold;// Удаление старой вершины-;// Уменьшение количества элементов в
стекеbuf;
}
// Удалить лишние элементы стека при превышении
макс. количества
template<class
sType>lastActionStack<sType>::reduce()
{dif = count -
StaticUndoStack::MaxActionsNum;(dif > 0)
{(int i=0; i<dif; i++)
{= bottom->next; // Обновляем
дно
стекаbottom->prev;
count--; // Удаляем элемент
со
дна
стека,
}
}
}.hperson;reservation;flight;data;
// Рейсflight
{number;// Номер
рейсаdays[7];//
Дни
неделиDeparturePoint[50];
// Пункт
отправленияDestinationPoint[50];
// Пункт
назначения
char DepartureTime[10]; // Время
отправленияclassType[3];// Количество по классамprice[3];// Цена на места по
классамreservNum;// Количество списков бронирования для
рейса<reservation> reserv;// Списки забронированных мест на данный рейс
на
// разные
даты:
~flight() {reserv.clear();}()
{reservNum=0;}restoreDays(); // Пересборка
дней
void reducePeopleLists(); // Уменьшение списка
забронированных мест при
// необходимостиfromFile(ifstream
&in);toFile(ofstream &out);
// Get- и
Set-методы<reservation>&
getReserv() {return reserv;}getNumber() {return number;}& СlassType(int
i) {return classType[i];}setClassType(String^ cl1, String^ cl2, String^
cl3);& Price(int i) {return price[i];}setPrice(String^ pr1, String^ pr2,
String^ pr3);getReservNum() {return reservNum;}setReservNum(int n) {reservNum =
n;}setNumber(int n) {number = n; }& Day(int i) {return days[i];}^
getDeparturePoint() { returngcnew String(DeparturePoint); }^
getDestinationPoint() { returngcnew String(DestinationPoint); }^
getDepartureTime() { returngcnew String(DepartureTime); }setDeparturePoint
(String^ s) { strcpy(DeparturePoint,
(char*)(void*)Marshal::StringToHGlobalAnsi(s));
}setDestinationPoint (String^ s) { strcpy(DestinationPoint,
(char*)(void*)Marshal::StringToHGlobalAnsi(s));
}setDepartureTime (String^ s) { strcpy(DepartureTime,
(char*)(void*)Marshal::StringToHGlobalAnsi(s));
}
};
// Список
бронированияreservation
{<person> people; // Список
людей
на
данный
рейс
int reserved[3];// Количество занятых мест по
классам
char date[30];// Дата
:() {reserved[0]=0; [1]=0; [2]=0;}
~reservation() { people.clear();}
// Get- и
Set-методы&
Reserved(int i) {return reserved[i];}^ getDate() { returngcnew String(date);
}setDate (String^ s) {
strcpy(date,(char*)(void*)Marshal::StringToHGlobalAnsi(s));
}<person>& getPeople() {return people;}fromFile(ifstream
&in);toFile(ofstream &out);
};
// Информация о человеке, бронировавшем
местоperson
{name[50]; // Полное
имяplaceType;//
Тип
места:(){name[0]='\0';
placeType=0; }(String^ s, char t) { strcpy(name,(char*)(void*)Marshal::StringToHGlobalAnsi(s));
placeType=t; }
// Get- и
Set-методы^
getName() { returngcnew String(name); }getPlaceType() {return
placeType;}setName(String^ s) {
strcpy(name,(char*)(void*)Marshal::StringToHGlobalAnsi(s)); }setPlaceType (int
t) {placeType = t;}
};data
{:list<flight> lst; // Список
авиарейсовlist<flight>::iterator
iter; // Итератор контейнера
listflight currentFlight;// Объект
класса
flightautosaveInterval;// Период
автосохранения
(мин)loadFromFile();//
Загрузить
данные
из
файла
staticvoid saveToFile();// Сохранить данные в
файл
};.cpp
#define Month 31
// Загрузить
из
файлаdata::loadFromFile()
{flightsIn;daysIn;peopleIn;{.open("flights.dat",
ios::in | ios::binary);.open("days.dat", ios::in |
ios::binary);.open("people.dat", ios::in | ios::binary);(!flightsIn.is_open()
|| !daysIn.is_open() || !peopleIn.is_open()) throw
fileError("1","Ошибка
открытия
файла");.read((char*)&autosaveInterval,
sizeof(int)); // Чтение периода
// автосохраненияnum;.read((char*)&num,
sizeof(int));// Чтение макс.
количества
// отменяемых
действий::MaxActionsNum
= num;// Утановка макс.
// количества
отменяемых
действий<flight>::iterator
iterator;.read((char*)&num, sizeof(int)); // Чтение
количества
авиарейсов(int
k=0; k<num; k++)
{.push_back(currentFlight); // Заполняем
контейнер
lst
// объектом класса flight= lst.end()--; //
Итератор на последний элемент lst
(*iterator).fromFile(flightsIn); // Читаем
рейс
из
файла
// Загрузка
дней(int
i=0; i<(*iterator).getReservNum(); i++)
{
// Увеличиваем размерность вектора reserv на 1
(*iterator).getReserv().resize((*iterator).getReserv().size()+1);(*iterator).getReserv()[i].fromFile(daysIn);
// Читаем
информацию
о
// вылете рейса по дням
// Загрузка информации о забронированных местах
для каждого дня
int num = (*iterator).getReserv()[i].Reserved(0)
+ (*iterator).getReserv()[i].Reserved(1) +
(*iterator).getReserv()[i].Reserved(2);(int j=0; j<num; j++)
{
(*iterator).getReserv()[i].getPeople().resize((*iterator).getReserv()[i].getPeople().size()+1);.read((char*)&(*iterator).getReserv()[i].getPeople()[j],
sizeof(person)); // Читаем информацию
о
человеке
}
}
}
} catch (baseException &e)
{ .showException(); // Вывод
исключения
// Закрытие файлов при
необходимости(flightsIn.is_open()) flightsIn.close();
if(daysIn.is_open()) daysIn.close();(peopleIn.is_open())
peopleIn.close();
}
}
// Записать
в
файлdata::saveToFile()
{flightsOut;daysOut;peopleOut;{.open("flights.dat",
ios::out | ios::binary);.open("days.dat", ios::out |
ios::binary);.open("people.dat", ios::out | ios::binary);(!flightsOut.is_open()
|| !daysOut.is_open() || !peopleOut.is_open()) throw
fileError("1","Ошибка
открытия
файла");.write((char*)&autosaveInterval,
sizeof(int)); // Запись периода
// автосохраненияnum
= StaticUndoStack::MaxActionsNum;// Макс.
количество
отменяемых
// действий.write((char*)&num,
sizeof(int));// Запись макс.
количества
// отменяемых
действий<flight>::iterator
iterator;= lst.size();// Количество
авиарейсов.write((char*)&num,
sizeof(int)); // Читаем количество
авирейсов
из
// файла
// Запись
авиарейсов(iterator=lst.begin();
iterator!=lst.end(); iterator++)
{
(*iterator).toFile(flightsOut); // Записываем
рейс в файл
// Запись информации о днях
for(unsignedint i=0;
i<(*iterator).getReserv().size(); i++)
{
(*iterator).getReserv()[i].toFile(daysOut);
// Запись информации о забронированных
местах(unsignedint j=0;j<(*iterator).getReserv()[i].
getPeople().size();
j++).write((char*)&(*iterator).getReserv()[i].getPeople()[j],
sizeof(person)); // Записываем
информацию
о
человеке
}
}
} catch (baseException &e)
{ .showException(); // Вывод
исключения
// Закрытие
файлов
при
необходимости(flightsOut.is_open())
flightsOut.close();(daysOut.is_open()) daysOut.close();(peopleOut.is_open())
peopleOut.close();
}
}
// Пересборка
днейflight::restoreDays()
{dateValue = DateTime::Now; // Текущая
дата
int day;// Номер дня недели
// Удаление дат до сегодняшнего дня и лишних
дней
vector<reservation>::iterator
itr = reserv.begin(); // Итератор
на
начало
списка
// дней(itr!=reserv.end())
{
// Очередная
дата
из
списка=
Convert::ToDateTime((*itr).getDate());
if(dateValue.Date < DateTime::Now.Date)//
Если дата до сегодняшнего дня
{= reserv.erase(itr); // Удаляем запись-;//
Уменьшаем количество дней;
}
(int) dateValue.DayOfWeek == 0 ? day = 6: day =
(int)dateValue.DayOfWeek-1; // Получаем ноиер дня недели из списка(!days[day])
// Если рейс не летает в данный день недели
{= reserv.erase(itr); // Удаляем запись-;//
Уменьшаем количество дней
}itr++;
}(reserv.size()) // Если список дней не пуст
{= reserv.begin();=
Convert::ToDateTime((*itr).getDate());
// Если первая в списке дата - сегодня,то
удаляем её
if(dateValue.Date ==
DateTime::Now.Date) reserv.erase(itr);
}
// Добавление недостающих дат=
DateTime::Now.AddDays(1);// Начальная дата
DateTime dateValueMax =
DateTime::Now.AddDays(Month); // Максимальная
датаnewDate;=
reserv.begin();^s="";(dateValue.Date <= dateValueMax.Date)
{
(int) dateValue.DayOfWeek == 0 ? day
= 6: day = (int)dateValue.DayOfWeek-1; // Номер
дня
недели
очередной
даты
// Если в этот день недели рейс
выполняется(days[day])
{(itr!=reserv.end()) // Если не достигнут конец
списка дней
{ String^ s= (*itr).getDate();
=DateTime::Parse(s);} // Очередная
дата
из
списка
// Если достигнут конец списка дней, или
следующая дата не совпадает
// с датой из списка(itr==reserv.end() ||
dateValue.Date != newDate.Date)
{
// вставляем элемент в список дней=
reserv.insert(itr,reservation());
// устанавливаем данную дату
(*itr).setDate(dateValue.Date.ToShortDateString());
++;// увеличиваем количество дней для данного рейса
}++;
}= dateValue.AddDays(1); // Переходим к
следующей дате
}
}
// Уменьшение списка забронированных мест при
уменьшении их максимального количества
void flight::reducePeopleLists()
{(int i = 0; i < reserv.size();
i++) // Проход
по
списку
дней
{(int cl=0; cl<3; cl++)// Для каждого типа
места
// Если забронировано больше мест, чем возможно
if(reserv[i].Reserved(cl) >
classType[cl])
// Проход по списку мест с конца
for (int j =
reserv[i].getPeople().size()-1; j>=0; j--)
// Если
место
рассматриваемого
типа(reserv[i].getPeople()[j].getPlaceType()==cl+1)
{[i].getPeople().erase(reserv[i].getPeople().begin()+j); // Удаляем
его
reserv[i].Reserved(cl)--;
// Если количество уменьшено до максимального,
// то
прекращаем
цикл(reserv[i].Reserved(cl)
== classType[cl])
break;
}
}
}
// Запись необходимых полей класса в файловый
поток
void flight::toFile(ofstream
&out)
{.write((char*)&number,sizeof(int));.write((char*)&days,sizeof(days));.write((char*)&DeparturePoint,sizeof(DeparturePoint));.write((char*)&DestinationPoint,sizeof(DestinationPoint));.write((char*)&DepartureTime,sizeof(DepartureTime));.write((char*)&classType,sizeof(classType));.write((char*)&price,sizeof(price));.write((char*)&reservNum,sizeof(int));
}
// Чтение необходимых полей класса из файлового
потока
void flight::fromFile(ifstream
&in)
{.read((char*)&number,sizeof(int));.read((char*)&days,sizeof(days));.read((char*)&DeparturePoint,sizeof(DeparturePoint));.read((char*)&DestinationPoint,sizeof(DestinationPoint));.read((char*)&DepartureTime,sizeof(DepartureTime));.read((char*)&classType,sizeof(classType));.read((char*)&price,sizeof(price));.read((char*)&reservNum,sizeof(int));
}
// Установка
типов
местflight::setClassType(String^
cl1, String^ cl2, String^ cl3)
{[0] = Convert::ToInt32(cl1);[1] =
Convert::ToInt32(cl2);
classType[2] = Convert::ToInt32(cl3);
}
// Установка стоимости мест в зависимости от
типа
void flight::setPrice(String^ pr1,
String^ pr2, String^ pr3)
{[0] = Convert::ToInt32(pr1);[1] =
Convert::ToInt32(pr2);
price[2] = Convert::ToInt32(pr3);
}
// Запись необходимых полей класса в файловый
поток
void reservation::toFile(ofstream
&out)
{.write((char*)&reserved,sizeof(reserved));.write((char*)&date,sizeof(date));
}
// Чтение необходимых полей класса из файлового
потока
void reservation::fromFile(ifstream
&in)
{.read((char*)&reserved,sizeof(reserved));.read((char*)&date,sizeof(date));
}