Здравствуйте! Вот вторая моя программа, написанная на C++(Qt). Выношу на обсуждение её и http://sourceforge.net/projects/klen-library/files/0.0.7/xwel-0.0.7-lin-src.tar.gz/download?use_mirror=citylan.
http://sourceforge.net/projects/klen-library на SourceForge.net. Код под GNU GPL v2 - OpenSource.
Она предназначена для создания электронных книг, с централизованным хранением в базе данных SQLite3.
Этот код публикуется впервые. Его не было нигде, включая репозиторий программ Sisyphus от дистрибутива AltLinux. Там был только Клёст-кроссворд(0.1.9, 0.2.0). Комментируем http://sourceforge.net/projects/klen-library/files/0.0.7/electronic-library-beta-0.0.7-win-x86.exe/download?use_mirror=citylan.
Описание:
Страница книги представляет собой одну переменную QString Page.
Текст книги отображается в компоненте QTextEdit TextBook.
Текст в компоненте TextBook имеет форматирование документа HTML. Поэтому редактирование текста страницы осуществляется редактированием html-кода.
Стандартное сохранение идёт в базу данных. Но есть и возможность экспорта в файл.
Изображения хранятся, как в обычной html-странице - отдельно от текста в папке "temp". В тексте указывается путь.
При загрузке книги - во всех страницах происходит перезапись тегов изображения "<img src=":
QString str1;
int iFirst,
iLast,
iLength,
iSearch;
for(int i = 0; i < ListPages.count(); i++)
{
str1 = ListPages.at(i);
if(str1.indexOf("<img src=\"") != -1)
{
int z = 1;
iSearch = 0;
while(str1.indexOf("<img src=\"", iSearch) != -1)
{
if(z == 1) iSearch = -1;
if(iSearch == -1)
{
iFirst = str1.indexOf("<img src=\"", 0);
iLast = str1.indexOf("/temp/Image", 0);
z++;
}
else
{
iFirst = str1.indexOf("<img src=\"", iSearch);
iLast = str1.indexOf("/temp/Image", iFirst);
}
iFirst += 10;
iLength = iLast - iFirst;
str1.remove(iFirst, iLength);
str1.insert(iFirst, "/tmp/xwel");
ListPages.replace(i, str1);
iSearch = iLast;
}
}
}
Это актуально для переносимой версии. В этом случае необходимо будет поменять строку:str1.insert(iFirst, "/tmp/xwel");
наstr1.insert(iFirst, QApplication::applicationDirPath());//Текущая папка, из которой запущено приложение
Пароль книги хранится в открытом виде в переменной QString Password. strBook = "DROP TABLE Table" + sNumBook + ";";
QueryBook.exec(strBook);
strBook = "CREATE TABLE Table" + sNumBook + " (Pages VARCHAR, Images BLOB);";
QueryBook.exec(strBook);
...
//Сохранение страниц
if(ListPages.count() != 0)
for(int i = 0; i < ListPages.count(); i++)
{
QueryBook.prepare("INSERT INTO Table" + sNumBook + " (Pages) VALUES (?);");
QueryBook.bindValue(0, ListPages.at(i));
QueryBook.exec(/*strBook*/);
}
//Сохранение изображений
for(int i = 0; i < 75; i++)//Здесь видно - что сохраняются только 75 изображений(!) из 255 :(
{
if(ListImages[i].count() != 0)
{
QueryBook.prepare("INSERT INTO Table" + sNumBook + " (Images) VALUES (?);");
QueryBook.bindValue(0, ListImages[i]);
QueryBook.exec(/*strBook*/);
}
else break;
}
лично я просел на фразе "Этот код публикуется впервые"
Вот спекфайл, по которому можно собрать rpm-пакет для дистрибутива AltLinux или своего, основанного на rpm:
Здравствуйте!
Следующая версия программы 0.0.8. http://sourceforge.net/projects/klen-library/files/0.0.8/. Её ключевой особенностью является импорт html-файла. Вот функция:
void ElectronicLibrary::OpenHTMLFile()
{
QString FileNameBook, str, sHTML;
FileNameBook = QFileDialog::getOpenFileName(0, tr("Book import"), "", "*.html");
if(FileNameBook == "") return;
else
{
QFile ifile(FileNameBook);
QTextStream istream(&ifile);
float i = 0;//Величина %
float ipt,//Численное значние "pt"
iptc;//Отвечает за таблицу
iptc = 0;
ipt = 0;
ifile.open(QIODevice::ReadOnly);
while(!ifile.atEnd())
{
str.append(istream.readLine());
str.append(" ");
sHTML.append(str);
if(str.indexOf("<TABLE") != -1) iptc = 1;//Начало таблицы
if(str.indexOf("/TABLE>") != -1) iptc = 2;//Конец таблицы
int j, iptc2;
QString s1,s2;
s1.clear();
s2.clear();
iptc2 = 0;
//Поиск элемента обозначения шрифта
j = str.indexOf("font-size:");
//Если элемент найден и найдено вхождение "pt", то
if(j != -1 && str.indexOf("pt", j) != -1)
{
//Добавление одной цифры, стоящей за "pt"
s1.append(str.at(str.indexOf("pt", j) - 1));
//Если второй символ стоящий за первым числом не пробел, то
if(str.at(str.indexOf("pt", j) - 2) != ' ')
//Добавить его как вторую цифру числа шрифта(ex. "14pt")
s2.append(str.at(str.indexOf("pt", j) - 2));
//Соединить с первой цифрой в s1. Образовать число.
if(s2 != "") s1.append(s2);
bool bOk;
ipt = s1.toFloat(&bOk);
//6pt = 113 = 0.885% от страницы
//16pt = 42 = 2.380% от страницы
//0.1375 - условный средний коэффициент % занимаемого значения 6pt на одной странице, формата A4
//Усреднённая формула нахождения % текущей строки от страницы, формата A4, относительно 6pt
ipt = (ipt / 6) * 0.1375;
}
//Поиск элемента обозначения шрифта другой формы
if(j == -1)
{
if(str.indexOf("FONT SIZE=1") != -1) j = 1;
if(str.indexOf("FONT SIZE=2") != -1) j = 2;
if(str.indexOf("FONT SIZE=3") != -1) j = 3;
if(str.indexOf("FONT SIZE=4") != -1) j = 4;
if(str.indexOf("FONT SIZE=5") != -1) j = 5;
if(str.indexOf("FONT SIZE=6") != -1) j = 6;
if(str.indexOf("FONT SIZE=7") != -1) j = 7;
switch(j)//Вычисление процента
{
case 1:
ipt = (8 / 6) * 0.1375;
case 2:
ipt = (10 / 6) * 0.1375;
case 3:
ipt = (12 / 6) * 0.1375;
case 4:
ipt = (14 / 6) * 0.1375;
case 5:
ipt = (18 / 6) * 0.1375;
case 6:
ipt = (24 / 6) * 0.1375;
case 7:
ipt = (36 / 6) * 0.1375;
}
}
i += ipt;//Суммирование процента
if(i >= 100)//Если набралось 100%
{
if(iptc == 0)//Если нет таблицы в конце страницы
{
sHTML.append("</body></html>");
ListPages << sHTML;
sHTML.clear();
sHTML.append("<html><body>");
i = 0;
}
else
{
//Если таблица была закрыта на данной странице
if(iptc == 2)
{
sHTML.append("</body></html>");
ListPages << sHTML;
sHTML.clear();
sHTML.append("<html><body>");
i = 0;
iptc = 0;//Значение = таблиц нет
}
}
}
str.clear();
}
if(sHTML != "") ListPages << sHTML << "</body></html>";
ifile.close();
if(gRegimeViewing == true) return;
}
Она производит разбивку на страницы, подсчитывая условное значение количества строк располагаемых на странице, формата A4. Была ещё задумка подсчитать количество символов в строке но, пока решил остановиться на таком варианте.Теперь и счастливым обладателям дистрибутивов GNU / Linux Debian и его производным(Ubuntu), предоставилась возможность попробовать себя в качестве разработчиков ПО.
Новая версия электронной библиотеки 0.0.9. http://sourceforge.net/projects/klen-library/files/0.0.9/.
Серьёзным изменением в данной версии является ускорение загрузки книги из базы данных. Это связано с выгрузкой изображений из базы на диск в папку. Сначала я не знал, как сделать лучше, поэтому сделал выгрузку по одному байту, что занимало большой промежуток времени.
При использовании объекта QImage - этот процесс уcкорился на моей тестовой машине раз в 20(!). Код ниже:
for(int i = 0; i < 75; i++)
if(ListImages[i].count() != 0)
{
QString sNumImage;
QByteArray sByteImage;
sByteImage.clear();
sNumImage.setNum(i);
if(i >= 0 && i <= 9) sNumImage.insert(0,"0");
ifile.setFileName("/tmp/xwel/temp/Image" + sNumImage + ".png");
QDataStream sifile(&ifile);
uchar cdata;
ifile.open(QIODevice::WriteOnly);
sByteImage.append(ListImages[i]);
while(sByteImage.count() != 0)
{
cdata = uchar(sByteImage.at(0));
sifile << cdata;
sByteImage.remove(0, 1);
}
if(i > SelectWordDialog->value()) SelectWordDialog->setValue(i);
QApplication::processEvents();
if(SelectWordDialog->wasCanceled()) break;
}
for(int i = 0; i < CountImages; i++)
if(ListImages[i].count() != 0)
{
QString sNumImage;
QByteArray sByteImage;
sByteImage.clear();
sNumImage.setNum(i);
if(i >= 0 && i <= 9) sNumImage.insert(0,"0");
sByteImage.append(ListImages[i]);
QImage ImageSave;
ImageSave.loadFromData(sByteImage);
ImageSave.save("/tmp/xwel/temp/Image" + sNumImage, "PNG");
if(i > SelectWordDialog->value()) SelectWordDialog->setValue(i);
QApplication::processEvents();
if(SelectWordDialog->wasCanceled()) break;
}
Здравствуйте!
В этой версии я сделал одно важное изменение, на которое хотел бы обратить Ваше особое внимание. Это функция "int slotChangeFont()". Там я копирую в переменную QString sText всё выделение:
sText = TextBook->textCursor().selection().toHtml();
Потом заменяю все вхождения модификаторов шрифта: "font-family:", "font-size:", "font-style:", "font-weight:" на значения из диалога шрифта.Здравствуйте! Вот новая версия 0.1.1 - http://sourceforge.net/projects/klen-library/files/0.1.1/.
Внешний вид:
http://radikal.ru/F/i077.radikal.ru/1108/21/8ca3afbf8ffb.jpg.html
Одно из добавлений - это функция поиска текста по книге:
while(iNumberPage < ListPages.count())
{
lFind:
if(TextBook->find(sFindText) == false)
{
slotNextPage(); //iNumberPage++
if(iNumberPage == ListPages.count() - 1) break;
goto lFind;
}
else break;
}
QFont TextFont;
TextFont = QFontDialog::getFont(&Accept, TextFont);
QTextCharFormat tcf;
tcf.setFont(TextFont);
TextBook->textCursor().setCharFormat(tcf);
--------------------------Здравствуйте! http://sourceforge.net/projects/klen-library/files/0.1.3/ содержит добавление защиты документов дополнительной информации от случайного изменения в режиме просмотра:
connect(ListAdditionallyWidget, SIGNAL(doubleClicked(QModelIndex)), SLOT(slotRunFile()));
void ListAdditionally::slotRunFile()
{
if(*sItem == tr("Documents") && gRegime == true)
{
QString sTmp;
sTmp = ListAdditionallyWidget->item(ListAdditionallyWidget->currentRow())->text();
int ipos = sTmp.lastIndexOf("/") + 1;
sTmp.remove(0, ipos);
QFile ifile(ListAdditionallyWidget->item(ListAdditionallyWidget->currentRow())->text());
QDataStream idata(&ifile);
QByteArray bfile;
ifile.open(QIODevice::ReadOnly);
bfile = ifile.readAll();
QFile ofile("/tmp/xwel/tempfile/" + sTmp);
QDataStream odata(&ofile);
ofile.open(QIODevice::WriteOnly);
ofile.write(bfile);
ifile.close();
ofile.close();
QDesktopServices::openUrl(QUrl::fromLocalFile("/tmp/xwel/tempfile/" + sTmp));//Открытие копии документа
}
else
//Открытие оригинала документа
QDesktopServices::openUrl(QUrl::fromLocalFile(ListAdditionallyWidget->item(ListAdditionallyWidget->currentRow())->text()));
}
То бишь, происходит простое копирование во временный файл документа и его запуск. Но, есть одно небольшое ограничение, при использовании такого подхода(bfile = ifile.readAll() - файл читается в переменную полностью и он не должен быть слишком большим. А все изменения выглядят вот так:В версии 0.1.4 http://sourceforge.net/projects/klen-library/files/0.1.4/ функция печати:
void ElectronicLibrary::slotPrint()
{
QPrinter printer;
QPrintDialog *pPrintDialog = new QPrintDialog(&printer);
if(pPrintDialog->exec() == QDialog::Accepted)
{
QPainter painter(&printer);
QRect r(painter.viewport());
if(ListPages.count() > 0)
{
for(int i = 0; i < ListPages.count(); i++)
{
TextBook->setHtml(ListPages.at(i));
painter.drawText(r, TextBook->toPlainText());
printer.newPage();
}
painter.end();
}
TextBook->setHtml(ListPages.at(0));
sbNumberPage.setValue(1);
}
delete pPrintDialog;
}
Такой вариант печатает простой текст, без форматирования и изображений.Здравствуйте! http://sourceforge.net/projects/klen-library/files/0.1.8/
//Изменение таблицы
void KlenLibrary::slotResizeTable()
{
if(gRegimeViewing == true) return;
InputParametrTable FormInputParametrTable;
FormInputParametrTable.setWindowTitle(tr("Change table parametrs"));
if(FormInputParametrTable.exec() == QDialog::Accepted)
{
if(FormInputParametrTable.SpinColumnCount->value() > 0
&& FormInputParametrTable.SpinColumnCount->value() > 0)
{
TextBook->textCursor().currentTable()->resize(FormInputParametrTable.SpinRowCount->value(),
FormInputParametrTable.SpinColumnCount->value());
}
}
}
currentTable() позволяет работать с таблицей, по текущей позиции курсора в тексте.В версии 0.1.9 добавлена работа с несколькими библиотеками-базами(как и в тесте ) и возможность резервировать со сжатием:
void KlenLibrary::slotBackupLibrary()
{
QString sNameBackupLibrary = QFileDialog::getSaveFileName(0, tr("Backup library"), "", "*.xwlbz");
if(sNameBackupLibrary == "") return;
if(sNameBackupLibrary.indexOf(".xwlbz") == -1) sNameBackupLibrary += ".xwlbz";
QFile ifile(sNameLibrary);
ifile.open(QIODevice::ReadOnly);
QByteArray baExport;
baExport = ifile.readAll();
ifile.close();
baExport = qCompress(baExport, 9);//Сжатие данных - 9-ая степень
QFile ofile(sNameBackupLibrary);
ofile.open(QIODevice::WriteOnly);
ofile.write(baExport);
ofile.close();
}
void KlenLibrary::slotRestoreLibrary()
{
QString sNameBackupLibrary = QFileDialog::getOpenFileName(0, tr("Open backup"), "", "*.xwlbz");
if(sNameBackupLibrary == "") return;
QFile ifile(sNameBackupLibrary);
ifile.open(QIODevice::ReadOnly);
QByteArray baImport;
baImport = ifile.readAll();
ifile.close();
baImport = qUncompress(baImport);//Извлечение данных из архива
sNameBackupLibrary = QFileDialog::getSaveFileName(0, tr("Restore library"), "", "*.xwlb");
if(sNameBackupLibrary.indexOf(".xwlb") == -1) sNameBackupLibrary += ".xwlb";
if(sNameBackupLibrary == "") return;
QFile ofile(sNameBackupLibrary);
ofile.open(QIODevice::WriteOnly);
ofile.write(baImport);
ofile.close();
}
Несколько изменений:Здравствуйте! Оптимизирована функция изменения шрифта:
bool Accept;
QFont TextFont;
TextFont = TextQuestion->textCursor().charFormat().font();
TextFont = QFontDialog::getFont(&Accept, TextFont);
if(Accept)
{
QTextCharFormat tcf;
tcf.setFont(TextFont);
TextQuestion->textCursor().setCharFormat(tcf);
cbFont.setCurrentFont(TextFont);
}
else return 1;
и другие изменения.Здравствуйте! Новый код. Версия 1.0.0 - это первая версия, в которой можно нормально работать с изображениями. Их количество теперь будет ровно таким, каким и должно быть, не больше.
Повышена безопасность программы перемещением некоторых переменных в секцию private: Теперь доступ к ним осуществляется из методов:
...
int TTextBook::isCountPages() const
{
return ListPages.count();
}
int TTextBook::isNumberBook() const
{
return i_NumberBook;
}
void TTextBook::setNumberBook(int iNumberBook)
{
i_NumberBook = iNumberBook;
}
int TTextBook::isYear() const
{
return i_Year;
}
void TTextBook::setYear(int iYear)
{
i_Year = iYear;
sYear.setNum(iYear);
}
int TTextBook::isCurrentPage() const
{
return i_CurrentPage;
}
void TTextBook::setCurrentPage(int iCurrentPage)
{
i_CurrentPage = iCurrentPage;
}
int TTextBook::isModeWork() const
{
return b_ModeWork;
}
void TTextBook::setModeWork(bool bModeWork)
{
b_ModeWork = bModeWork;
}
QByteArray TTextBook::isPassword() const
{
return ba_Password;
}
void TTextBook::setPassword(QByteArray baPassword)
{
ba_Password = baPassword;
}
...
//Исправлена печать - печатается весь текст :)
void TTextBook::slotPrint()
{
QPrinter printer;
QPrintDialog *pPrintDialog = new QPrintDialog(&printer);
QTextDocument *textDoc = new QTextDocument;
QString sPrint;
if(pPrintDialog->exec() == QDialog::Accepted)
{
sPrint = makeOneHTML();
QImage textImage;
for (int i = 0; i < ListImages.count(); i++)
{
textImage.loadFromData(ListImages.at(i));
textDoc->addResource(QTextDocument::ImageResource, QUrl(slNumberImages.at(i)), textImage);
}
textDoc->setHtml(sPrint);
textDoc->print(&printer);
}
delete textDoc;
delete pPrintDialog;
}
Здравствуйте!
Новая версия. 1.0.5. Тут прошу особо протестировать Mac- и Linux-установщики, так как Linux-пакетов больше нет. http://sourceforge.net/projects/klen-library/files/1.0.5/
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)