3 Индивидуальное задание
Разработать набор классов (минимум 5 классов) по теме использование текстового редактора пользователями с автоматическим сохранением данных в файл. Редактор должен поддерживать возможность отмены внесенных изменений (отменить ввод, Undo, Ctrl+Z) и восстановления отмененной информации (вернуть ввод, Ctrl+Y, Redo). Для хранения историй модификации файла использовать список (его рациональную организацию определить самостоятельно). Разработанный набор классов должен иметь параметры типа. Все классы должны иметь методы получения и изменения своих полей. Использовать smart-указатели для создания программы, которая определяет возможность самостоятельного закрытия файла (т.е. данные файла сохранены и с ним никто сейчас не работает).
4 Код решения индивидуального задания
“input.h”
#pragma once
#pragma once
#include <iostream>
#include <conio.h>
#include <cstring>
void input(int& number)
{
int index = 0;
char str[4 + 1];
char ch;
bool sign = false;
do {
ch = _getch();
if (index == 0 && ch == '-' && !sign)
{
sign = true;
std::cout << "-";
}
else if (index == 0 && ch == 8 && sign)
{
std::cout << "\b \b";
sign = false;
}
if (ch == '\r' && index == 0)
{
ch = 0;
}
else if (index == 0 && ((ch >= '0' && ch <= '9')) && ch != 8)
{
std::cout << ch;
str[index] = ch;
index++;
}
else if (index > 0)
{
if (ch == 8)
{
index--;
str[index] = '\0';
std::cout << "\b \b";
}
else if (index >= 4)
{
;
}
else if (ch >= '0' && ch <= '9')
{
std::cout << ch;
str[index] = ch;
index++;
}
}
} while (ch != '\r');
str[index] = '\0';
std::cout << std::endl;
number = atoi(str);
if (sign) number *= -1;
}
void inputLat(std::string& str, int length)
{
int index = 0;
char ch;
do
{
ch = _getch();
if (ch == '\r' && index == 0)
{
ch = 0;
}
else if (ch == 8 && index > 0)
{
index--;
str.erase(index);
std::cout << "\b \b";
}
else if (index < 0 || index >= length)
{
;
}
else if ((ch >= '0' && ch <= '9') || ch == ' ' || ch == '№' || ch == '/' || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= 'а' && ch <= 'я') || (ch >= 'А' && ch <= 'Я') || (ch == 'ё' || ch == 'Ё'))
{
std::cout << ch;
str.push_back(ch);
index++;
}
} while (ch != '\r');
std::cout << std::endl;
}
“input.cpp”
#include <iostream>
#include <fstream>
#include <vector>
#include <iomanip>
#include <Windows.h>
#include "input.h"
using namespace std;
ostream& date(ostream& stream, int year, int day, int month)
{
if (day < 10) cout << "0";
cout << day << ".";
if (month < 10) cout << "0";
cout << month << ".";
cout << year;
return stream;
}
class Employee
{
public:
string name;
string place;
static const string file;
void output()
{
cout << name;
cout << " || " << place << endl;
}
void fwrite(ofstream& file)
{
for (int i = 0; i < name.size(); i++)
{
if (name.at(i) == ' ') name.at(i) = '.';
}
for (int i = 0; i < place.size(); i++)
{
if (place.at(i) == ' ') place.at(i) = '.';
}
file << name << endl;
file << place;
for (int i = 0; i < name.size(); i++)
{
if (name.at(i) == '.') name.at(i) = ' ';
}
for (int i = 0; i < place.size(); i++)
{
if (place.at(i) == '.') place.at(i) = ' ';
}
}
void fread(ifstream& file)
{
file >> name;
file >> place;
for (int i = 0; i < name.size(); i++)
{
if (name.at(i) == '.') name.at(i) = ' ';
}
for (int i = 0; i < place.size(); i++)
{
if (place.at(i) == '.') place.at(i) = ' ';
}
}
};
class Document
{
public:
static const string file;
string name;
string edInstitution;
int year;
int month;
int day;
void fwrite(ofstream& file)
{
for (int i = 0; i < name.size(); i++)
{
if (name.at(i) == ' ') name.at(i) = '.';
}
for (int i = 0; i < edInstitution.size(); i++)
{
if (edInstitution.at(i) == ' ') edInstitution.at(i) = '.';
}
file << name << endl;
file << edInstitution << endl;
file << year << endl;
file << month << endl;
file << day;
for (int i = 0; i < name.size(); i++)
{
if (name.at(i) == '.') name.at(i) = ' ';
}
for (int i = 0; i < edInstitution.size(); i++)
{
if (edInstitution.at(i) == '.') edInstitution.at(i) = ' ';
}
}
void fread(ifstream& file)
{
file >> name;
file >> edInstitution;
file >> year;
file >> month;
file >> day;
for (int i = 0; i < name.size(); i++)
{
if (name.at(i) == '.') name.at(i) = ' ';
}
for (int i = 0; i < edInstitution.size(); i++)
{
if (edInstitution.at(i) == '.') edInstitution.at(i) = ' ';
}
}
void output()
{
cout << "|| " << setiosflags(ios::left) << setw(25) << name;
cout << " | " << setw(20) << edInstitution;
cout << " | ";
date(cout, year, day, month) << endl;
}
void input()
{
cout << "Название документа : ";
inputLat(name, 25);
cout << "ВУЗ : ";
inputLat(edInstitution, 20);
cout << "Срок сдачи задания студентами" << endl;
cout << "День : ";
::input(day);
cout << "Месяц : ";
::input(month);
cout << "Год : ";
::input(year);
}
void inputTransaction(string edInstitution)
{
this->edInstitution = edInstitution;
cout << "Название документа : ";
inputLat(name, 25);
cout << "Срок сдачи задания студентами" << endl;
cout << "День : ";
::input(day);
cout << "Месяц : ";
::input(month);
cout << "Год : ";
::input(year);
}
void set(Document doc)
{
this->day = doc.day;
this->month = doc.month;
this->year = doc.year;
this->name = doc.name;
this->edInstitution = doc.edInstitution;
}
};
template <class T>
class Transaction
{
public:
T* prevState;
T* currentState;
Transaction(T* doc) {
prevState = NULL;
currentState = new T;
currentState = doc;
}
~Transaction() { delete currentState; delete prevState; }
void show()
{
cout << "состояния объекта" << endl;
if (prevState)
{
cout << "prevState = " << endl;
prevState->output();
cout << endl;
cout << "currentState = " << endl;
currentState->output();
cout << endl;
}
else
{
cout << "prevState = NULL" << endl;
cout << "currentState = " << endl;
currentState->output();
cout << endl;
}
}
bool BeginTransactions(T* newState)
{
delete prevState;
prevState = currentState;
currentState = new T(*prevState);
if (!currentState) return 0;
currentState->set(*newState);
return 1;
}
void commit()
{
prevState = NULL;
}
void DeleteTransactions()
{
if (prevState != NULL) {
currentState = NULL;
delete currentState;
currentState = prevState;
prevState = NULL;
}
}
T* operator->() { return currentState; };
};
template <class T>
struct Status {
T* ptr;
int counter;
};
template <typename T>
class SmartPointer {
Status<T>* smartPtr;
public:
static const string file;
SmartPointer(T* ptr = 0);
int showCounter() { return smartPtr->counter; }
~SmartPointer() {
if (smartPtr) {
smartPtr->counter--;
if (smartPtr->counter <= 0) {
delete smartPtr->ptr;
delete smartPtr;
}
}
}
T* operator->() const
{
if (smartPtr) return smartPtr->ptr;
else return NULL;
}
T& getPtr() const { return *smartPtr->ptr; }
SmartPointer(const SmartPointer& obj) :smartPtr(obj.smartPtr) {
if (smartPtr) smartPtr->counter++;
}
};
template <class T>
SmartPointer<T>::SmartPointer(T* ptr) {
smartPtr = new Status<T>;
smartPtr->ptr = ptr;
smartPtr->counter = 1;
}
template <class T>
class File
{
public:
static void fread(vector<SmartPointer<T>>& vect)
{
ifstream file(T::file);
while (!file.eof())
{
SmartPointer<T> newItem(new T);
newItem->fread(file);
vect.push_back(newItem);
}
file.close();
}
static void fwrite(vector<SmartPointer<T>> vect)
{
ofstream file(T::file);
for (int i = 0; i < vect.size(); i++)
{
vect.at(i)->fwrite(file);
if (i != vect.size() - 1) file << endl;
}
file.close();
}
};
const string Employee::file = "employee.txt";
const string Document::file = "document.txt";
template <class T>
void transactMenu(SmartPointer<T>& doc)
{
Transaction<T> transaction(&doc.getPtr());
SmartPointer<T> newDoc(new T);
while (true)
{
system("cls");
cout << "1)Начать транзакцию" << endl;
cout << "2)Откатить состаяние" << endl;
cout << "3)Просмотреть состояние транзакции" << endl;
cout << "4)Сохранить изменения и выйти" << endl;
cout << ">> ";
int choice;
::input(choice);
switch (choice)
{
case 1:
{
newDoc->inputTransaction(transaction.currentState->edInstitution);
transaction.BeginTransactions(&newDoc.getPtr());
break;
}
case 2:
{
transaction.DeleteTransactions();
break;
}
case 3:
{
system("cls");
transaction.show();
system("pause");
break;
}
case 4:
{
doc.getPtr() = *transaction.currentState;
transaction.commit();
system("cls");
transaction.show();
transaction = NULL;
system("pause");
return;
}
default: cout << "Неверный ввод" << endl; system("pause"); break;
}
}
}
void menu(SmartPointer<Employee> me)
{
vector<SmartPointer<Document>> vect;
File<Document>::fread(vect);
while (true)
{
system("cls");
cout << "1)Просмотр загруженных документов" << endl;
cout << "2)Меню транзакции" << endl;
cout << "3)Добавить документ с домашним заданием" << endl;
cout << "4)Удалить документ с домашним заданием" << endl;
cout << "5)Назад" << endl;
cout << ">> ";
int choice;
::input(choice);
switch (choice)
{
case 1:
{
if (!vect.size()) { cout << "Список пуст" << endl; system("pause"); break; }
system("cls");
cout << " " << setw(25) << " Название";
cout << " " << " ВУЗ";
cout << " " << " Срок сдачи задания студентами" << endl;
bool checking = false;
for (int i = 0; i < vect.size(); i++)
{
if (me->place == vect.at(i)->edInstitution)
{
vect.at(i)->output();
checking = true;
}
}
if (!checking) {
cout << "Нет доступных документов" << endl;
}
system("pause");
break;
}
case 2:
{
if (!vect.size()) { cout << "Список пуст" << endl; system("pause"); break; }
system("cls");
cout << " " << setw(25) << " Название";
cout << " " << " ВУЗ";
cout << " " << "Срок сдачи задания студентами" << endl;
bool checking = false;
for (int i = 0; i < vect.size(); i++)
{
if (me->place == vect.at(i)->edInstitution)
{
vect.at(i)->output();
checking = true;
}
}
if (!checking) {
cout << "Нет доступных документов" << endl;
break;
}
system("pause");
string name;
cout << "Название документа : ";
inputLat(name, 25);
for (int i = 0; i < vect.size(); i++)
{
if (vect.at(i)->name == name)
{
transactMenu<Document>(vect.at(i));
File<Document>::fwrite(vect);
break;
}
}
break;
}
case 3:
{
system("cls");
SmartPointer<Document> newDoc(new Document);
newDoc->input();
vect.push_back(newDoc);
File<Document>::fwrite(vect);
break;
}
case 4:
{
if (!vect.size()) { cout << "Список пуст" << endl; system("pause"); break; }
system("cls");
cout << " " << setw(25) << " Название";
cout << " " << " ВУЗ";
cout << " " << "Срок сдачи задания студентами" << endl;
bool checking = false;
for (int i = 0; i < vect.size(); i++)
{
if (me->place == vect.at(i)->edInstitution)
{
vect.at(i)->output();
checking = true;
}
}
if (!checking) {
cout << "Нет доступных документов" << endl;
break;
}
system("pause");
string name;
cout << "Название документа : ";
inputLat(name, 25);
for (int i = 0; i < vect.size(); i++)
{
if (vect.at(i)->name == name)
{
vect.erase(i + vect.begin());
File<Document>::fwrite(vect); break;
}
}
cout << "Документ не найден" << endl;
system("pause");
break;
}
case 5: return;
default: cout << "Неверный ввод" << endl; system("pause"); break;
}
}
}
int main()
{
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
vector<SmartPointer<Employee>> empl;
File<Employee>::fread(empl);
while (true)
{
system("cls");
cout << "1)Вход" << endl;
cout << "2)Добавить преподавателя" << endl;
cout << "3)Просмотр списка преподавателей университета" << endl;
cout << "4)Выход" << endl;
cout << ">> ";
int choice;
::input(choice);
switch (choice)
{
case 1:
{
if (!empl.size())
{
cout << "Список пуст" << endl;
system("pause");
break;
}
system("cls");
string name;
cout << "Фамилия преподавателя : ";
inputLat(name, 25);
bool checking = false;
;
for (int i = 0; i < empl.size(); i++)
{
if (empl.at(i)->name == name)
{
menu(empl.at(i));
checking = true;
break;
}
}
if (!checking) cout << "Преподаватель не найден" << endl;
system("pause");
break;
}
case 2:
{
system("cls");
SmartPointer<Employee> newEm(new Employee);
cout << "Фамилия преподавателя : ";
inputLat(newEm->name, 25);
cout << "Университет : ";
inputLat(newEm->place, 30);
empl.push_back(newEm);
system("pause");
File<Employee>::fwrite(empl);
break;
}
case 3:
{
if (!empl.size())
{
cout << "Список пуст" << endl;
system("pause");
break;
}
system("cls");
for (int i = 0; i < empl.size(); i++)
{
cout << setiosflags(ios::left) << i + 1 << ". ";
empl.at(i)->output();
}
system("pause");
break;
}
case 4: return 0;
default: cout << "Неверный ввод" << endl; system("pause"); break;
}
}
}