Хотелось бы опубликовать статью на русском языке об интеграции роликов Silverlight в Qt приложения.
Для этого используется библиотека Qtitan, она коммерческая, увы, но может быть кого-то заинтересует. К тому же ее вполне можно использовать в демо-режиме в некоммерческих целях.
Статья публикуется с негласного соглашения авторов фреймворка Qtitan Multimedia.
Интеграция Silverlight в Qt приложения
Разработчики, которым довелось разрабатывать приложения на фреймворке Qt, любят его за удобство и простоту использования, и за мощность которая скрывается под капотом технологии.
Мы тоже любим Qt, и мы захотели расширить наш любимый фреймворк возможностью работы с современной векторной графикой, например, мы захотели интегрировать в приложение ролики Adobe Flash или Microsoft Silverlight.
вторник, 19 октября 2010 г.
среда, 13 октября 2010 г.
QScintilla: определяем styleText
Вот мы и добрались до самой важной функции лексера void styleText(int start, int end)
Займемся ее реализацией.
В комментариях описано, что мы делаем в этой функции. Здесь мы получаем строку, которую требуется отрисовать (это может быть не только текущая строка, а в том числе и соседние строки, сцинтилла в этом плане довольно умна).
Дальше вызываем функцию commentStyling(source, start, end);
Ее реализация приведена ниже:
Займемся ее реализацией.
void LexerZ::styleText(int start, int end)
{
//editor() - функция из родительского класса.
//Возвращает указатель на QsciScintilla
if (!editor())
return;
//получить исходник
//выделим кусок памяти
// +1 - под \0
char * chars = new char[end - start + 1];
//заполним кусок обратившись сцинтилле
editor()->SendScintilla(QsciScintilla::SCI_GETTEXTRANGE,
start, end, chars);
//преобразуем в строку
QString source(chars);
delete [] chars;
//Оптимизация - кэшируем уже ранее отрисованную строку
if (source == cache)
return;
else
cache = source;
//Не работаем с пустой строкой
if (source.isEmpty())
return;
//вызываем функцию отрисовки комментария
//передаем исходную строку, начало и конец
commentStyling(source, start, end);
}
* This source code was highlighted with Source Code Highlighter.
В комментариях описано, что мы делаем в этой функции. Здесь мы получаем строку, которую требуется отрисовать (это может быть не только текущая строка, а в том числе и соседние строки, сцинтилла в этом плане довольно умна).
Дальше вызываем функцию commentStyling(source, start, end);
Ее реализация приведена ниже:
понедельник, 11 октября 2010 г.
QScintilla: раскрашиваем комментарии
Сегодня мы будем раскрашивать комментарии для некого гипотетического языка Z.
Допустим в этом языке комментарии строк принято обозначать символом **, аналогично // в C++. Давайте предположим, что цвет шрифта комментария - синий, цвет фона - светло-зеленый, а сам шрифт - Comic Sans.
Начнем изменения в нашем коде Lexer.cpp и Lexer.h. (Можно переименовать эти файлы в LexerZ.h и LexerZ.cpp).
Допустим в этом языке комментарии строк принято обозначать символом **, аналогично // в C++. Давайте предположим, что цвет шрифта комментария - синий, цвет фона - светло-зеленый, а сам шрифт - Comic Sans.
Начнем изменения в нашем коде Lexer.cpp и Lexer.h. (Можно переименовать эти файлы в LexerZ.h и LexerZ.cpp).
пятница, 8 октября 2010 г.
QScintilla: пишем Lexer
Перед дальнейшим написанием лексера нужно уяснить парадигму паттерна "Виртуальный метод", который использует QScintilla.
Лескер состоит из набора виртуальный функций, которые нужно переопределить. Класс QsciScintilla при необходимости вызывает виртуальные методы базового класса, однако в соответствии с полиморфизмом, будут вызываться методы нашего лексера.
Вот перечень виртуальных функций, необходимых для переопределения:
Самой важной виртуальной функцией является virtual void styleText (int start, int end);
Именно она отвечает за отрисовку. К этой функции QScintilla обращается всякий раз, когда ей надо перерисовать кусок текста начиная с позиции start до позиции end.
Лескер состоит из набора виртуальный функций, которые нужно переопределить. Класс QsciScintilla при необходимости вызывает виртуальные методы базового класса, однако в соответствии с полиморфизмом, будут вызываться методы нашего лексера.
Вот перечень виртуальных функций, необходимых для переопределения:
//! Возвращает название языка
virtual const char * language() const;
//! Цвета для стилей
virtual QColor defaultColor(int style) const;
//! Шрифты для стилей
virtual QFont defaultFont(int style) const;
//! Бакгроунд для стилей
virtual QColor defaultPaper(int style) const;
//! Разбор текста на стили
virtual void styleText (int start, int end);
//! Описание
virtual QString description (int style) const;
* This source code was highlighted with Source Code Highlighter.
Переменная style - это просто идентификатор стиля. Мы сами ее определяем. Для этого в лексере мы определяем некий enum для наших стилей. enum
{
Default = 0,
Comment = 1,
Binary = 2,
String = 3,
Keyword1 = 4,
Keyword2 = 5,
Keyword3 = 6,
Keyword4 = 7,
Const = 8
};
* This source code was highlighted with Source Code Highlighter.
Имена стилей и их числовые обозначения значения не имеют, далее станет ясно почему.Самой важной виртуальной функцией является virtual void styleText (int start, int end);
Именно она отвечает за отрисовку. К этой функции QScintilla обращается всякий раз, когда ей надо перерисовать кусок текста начиная с позиции start до позиции end.
четверг, 7 октября 2010 г.
QScintilla: создаем свой лексер
Как уже было сказано ранее, QScintilla поддерживает около 80 языков, раскрашивая каждый в соответствии с их синтаксисом. Т.е. для C++ комментарии задаются символом //, а для языка R символом #. Соответственно, раскрашивать в каждом случае надо по своему.
Трудно представить, что кроме этих 80 языков вам может понадобиться что-то свое, но тем не менее такая ситуация возникнуть может и надо знать как тут поступать.
Вообще, есть два способа добавить свой язык для раскраски.
Первый - это правка собственно исходного кода библиотеки qscintilla2.dll.
Достоинства этого метода - простота добавления. Достаточно взять за пример уже какой-нибудь существующий лексер, скопировать его в новый файл, исправить несколько строк, пересобрать библиотеку и, вуаля, новый лексер готов.
Недостаток этого метода очевиден - необходимость пересобирать библиотеку. Хотелось бы обойтись без этого.
Для этого в QScintilla есть путь истинного воина - наследование от QsciLexerCustom и самостоятельное написание алгоритмов раскраски. Это более сложный путь, на мой взгляд, но зато более правильный с концептуальной точки зрения, т.к. не нужно пересобирать библиотеку.
Итак, первое что мы должны сделать - это отнаследоваться от QsciLexerCustom:
Трудно представить, что кроме этих 80 языков вам может понадобиться что-то свое, но тем не менее такая ситуация возникнуть может и надо знать как тут поступать.
Вообще, есть два способа добавить свой язык для раскраски.
Первый - это правка собственно исходного кода библиотеки qscintilla2.dll.
Достоинства этого метода - простота добавления. Достаточно взять за пример уже какой-нибудь существующий лексер, скопировать его в новый файл, исправить несколько строк, пересобрать библиотеку и, вуаля, новый лексер готов.
Недостаток этого метода очевиден - необходимость пересобирать библиотеку. Хотелось бы обойтись без этого.
Для этого в QScintilla есть путь истинного воина - наследование от QsciLexerCustom и самостоятельное написание алгоритмов раскраски. Это более сложный путь, на мой взгляд, но зато более правильный с концептуальной точки зрения, т.к. не нужно пересобирать библиотеку.
Итак, первое что мы должны сделать - это отнаследоваться от QsciLexerCustom:
#include <qsci/qscilexercustom.h>
class Lexer : public QsciLexerCustom
{
Q_OBJECT
public:
//! Конструктор
Lexer(QObject * parent = 0);
//! Деструктор
virtual ~Lexer();
private:
Lexer(const Lexer &);
Lexer &operator=(const Lexer &);
};
* This source code was highlighted with Source Code Highlighter.
В следующих выпусках мы продолжим написание своего лексера.
QScintilla: создание редактора
Сейчас мы создадим экземпляр QScintilla и зададим ему некоторые свойства.
В качестве языка для подсветки будем использовать C++.
http://www.riverbankcomputing.co.uk/static/Docs/QScintilla2/classQsciScintilla.html
В качестве языка для подсветки будем использовать C++.
#include <Qsci/qsciscintilla.h>
#include <Qsci/QsciLexerCPP.h>
//Создаем редактор
QsciScintilla * textEdit = new QsciScintilla(this);
//Создаем и устанавливаем лексер для C++
QsciLexerCPP * lexCpp = new QsciLexerCPP(this);
textEdit->setLexer(lexCpp);
//Задаем формат ввода - без этого не будут вводиться русские буквы
textEdit->setUtf8(true);
//Текущая строка подсвечивается горизонтальной линией
textEdit->setCaretLineVisible(true);
//Цвет линии
textEdit->setCaretLineBackgroundColor(QColor("gainsboro"));
//Автоматический отступ
textEdit->setAutoIndent(true);
textEdit->setIndentationGuides(true);
//Заменять Tab на пробелы
textEdit->setIndentationsUseTabs(false);
//Ширина отступа - 4 пробела
textEdit->setIndentationWidth(4);
//Задаем символ конца строки
#if defined Q_WS_X11
textEdit->setEolMode(QsciScintilla::EolUnix);
#elif defined Q_WS_WIN
textEdit->setEolMode(QsciScintilla::EolWindows);
#elif defined Q_WS_MAC
textEdit->setEolMode(QsciScintilla::EolMac);
#endif
//Задаем цвет вертикальной полосы слева - там где ставятся breakpoints, закладки, номера строк
textEdit->setMarginsBackgroundColor(QColor("gainsboro"));
//Отображать номера строк
textEdit->setMarginLineNumbers(1, true);
//Ширина полосы - такая чтобы влезли символы до 1000
textEdit->setMarginWidth(1, QString("1000"));
//Автозавершение лексем
textEdit->setAutoCompletionSource(QsciScintilla::AcsAll);
textEdit->setAutoCompletionCaseSensitivity(true);
textEdit->setAutoCompletionReplaceWord(true);
textEdit->setAutoCompletionShowSingle(true);
textEdit->setAutoCompletionThreshold(2);
//Автоподсветка скобок
textEdit->setBraceMatching(QsciScintilla::SloppyBraceMatch);
//Цвет подсветки - желный с синим
textEdit->setMatchedBraceBackgroundColor(Qt::yellow);
textEdit->setUnmatchedBraceForegroundColor(Qt::blue);
//Слот на сигнал - "документ изменился"
connect(textEdit, SIGNAL(textChanged()),
this, SLOT(documentWasModified()));
//Слот на сигнал - "курсор сместился"
connect(textEdit, SIGNAL(cursorPositionChanged(int, int)),
this, SLOT(cursorMoved(int, int)));
* This source code was highlighted with Source Code Highlighter.
За дополнительной информацией по редактору можно обращаться к документации:http://www.riverbankcomputing.co.uk/static/Docs/QScintilla2/classQsciScintilla.html
среда, 6 октября 2010 г.
QScintilla: собираем проект
Напишем pro файл для включения QScintilla в свой проект. Я не буду приводить весь файл, а укажу на что нужно обратить внимание.
В пределах видимости нужно расположить qscintilla2.dll и включить в INCLUDEPATH путь до заголовочных файлов QScintilla (например, QScintilla\Qt4\Qsci\).
После чего можно собирать проект.
- Конечно подключить библиотеку:
unix:LIBS += -lqscintilla2
win32:LIBS += qscintilla2.lib - Определить переменные
DEFINES += QSCINTILLA_DLL SCI_LEXER
Здесь определены 2 переменные. Первая говорит, что мы используем экспорт из библиотеки qscintilla2. Вторая, что мы определяем свой лексер. Лексер - это объект, который отвечает за отрисовку текста. Соответственно, если в планах нет желания писать свой лексер (например, для какого-нибудь особо экзотического языка), то переменную SCI_LEXER определять не нужно.
В пределах видимости нужно расположить qscintilla2.dll и включить в INCLUDEPATH путь до заголовочных файлов QScintilla (например, QScintilla\Qt4\Qsci\).
После чего можно собирать проект.
QScintilla: установка
Живет QScintilla здесь:
http://www.riverbankcomputing.co.uk/software/qscintilla/intro
Периодически выходят обновления, на сегодняшний день последняя версия - 2.4.5.
QScintilla портирована как для Qt 3, так и для Qt 4. С третьей версией я не работаю и не знаю насколько там все хорошо, но для четверки все нормально, ничего допиливать не надо.
О лицензии.
RiverBank распространяет QScintilla под тремя лицензиями:
Но способ обойти ограничение есть.
Установка.
В сборке библиотеки нет ничего сложного - скачиваем, распаковываем, переходим в каталог QScintilla/Qt4 и запускаем qmake -tp vc. В итоге получаем проект qscintilla2.vcproj.
Собираем его.
Получаем в итоге qscintilla2.dll и qscintilla2.lib, которые будем использовать в программе.
В следующем выпуске начнем работу с Qscintilla.
http://www.riverbankcomputing.co.uk/software/qscintilla/intro
Периодически выходят обновления, на сегодняшний день последняя версия - 2.4.5.
QScintilla портирована как для Qt 3, так и для Qt 4. С третьей версией я не работаю и не знаю насколько там все хорошо, но для четверки все нормально, ничего допиливать не надо.
О лицензии.
RiverBank распространяет QScintilla под тремя лицензиями:
- GNU General Public License v2
- GNU General Public License v3
- Riverbank Commercial License
Но способ обойти ограничение есть.
Как обмануть GPL:Вот такая неприятность.
Например, можно на сайте сделать два линка: один на коммерческую программу , а второй — на GPL драйвер(библиотеку). Две независимые работы можно скачать по отдельности.
Установка.
В сборке библиотеки нет ничего сложного - скачиваем, распаковываем, переходим в каталог QScintilla/Qt4 и запускаем qmake -tp vc. В итоге получаем проект qscintilla2.vcproj.
Собираем его.
Получаем в итоге qscintilla2.dll и qscintilla2.lib, которые будем использовать в программе.
В следующем выпуске начнем работу с Qscintilla.
QScintilla - продвинутый редактор для Qt
Открываю цикл статей о QScintilla. QScintilla это порт проекта Scintilla на Qt. Scintilla - это мощный кросплатформенный редактор текста.
В его возможности входит:
В итоге я хочу в своем блоге выложить все, что мне известно о работе с QScintilla.
В его возможности входит:
- Подсветка исходного кода различных языков. Поддерживается 78 самых известных языков (Abaqus, Ada, APDL, Asm, Asn1, ASY, AU3, AVE, Baan, Bash, Basic, Bullant, Caml, CLW, Cmake, COBOL, Conf, CPP, Crontab, Csound, CSS, D, Eiffel, Erlang, EScript, Flagship, Forth, Fortran, GAP, Gen.py, Gui4Cli, Haskell, HTML, Inno, Kix, Lisp, Lout, Lua, Magik, Matlab, Metapost, MMIXAL, MPT, MSSQL, MySQL, Nimrod, Nsis, Opal, Others, Pascal, PB, Perl, PLM, POV, PowerPro, PowerShell, Progress, PS, Python, R, Rebol, Ruby, Scriptol, Smalltalk, SML, Sorcus, Specman, Spice, SQL, TACL, TADS3, TAL, TCL, TeX, VB, Verilog, VHDL, YAML)
- Собственно редактирование кода и все, что с ним связано - отступы, cut/copy/paste, подсветка скобок и прочее. Возможностей - на полноценный текстовый редактор.
- Есть возможность добавить собственный язык и задать для него собственную раскраску.
В итоге я хочу в своем блоге выложить все, что мне известно о работе с QScintilla.
понедельник, 21 июня 2010 г.
Пишем в PDF русские символы и вообще Unicode
Продолжаем осваивать SDK PoDoFo для работы с pdf файлами.
Сегодня я расскажу как в pdf-файл записать Unicode строки.
Сегодня я расскажу как в pdf-файл записать Unicode строки.
вторник, 15 июня 2010 г.
Помещаем и извлекаем данные из PDF
Разобрался как работать с аттачами в PDF через PoDoFo (кстати он недавно обновился до 0.8.1).
Смысл в следующем - создается страница и к ней прикрепляется аннотация размером 0 на 0. Таких аннотаций на страницу может быть много. В качестве аннотации может быть текст, картинка или вложенный файл. Вот этим и воспользуемся.
Итак - сама страница будет отображать данные в красивом виде, таблички там и прочее. Это нам неинтересно на данном этапе. Сейчас важно научиться создавать вложенные файлы.
Смысл в следующем - создается страница и к ней прикрепляется аннотация размером 0 на 0. Таких аннотаций на страницу может быть много. В качестве аннотации может быть текст, картинка или вложенный файл. Вот этим и воспользуемся.
Итак - сама страница будет отображать данные в красивом виде, таблички там и прочее. Это нам неинтересно на данном этапе. Сейчас важно научиться создавать вложенные файлы.
четверг, 3 июня 2010 г.
PDF в Qt
Столкнулся со следующей задачей.
Нужно хранить некие данные (текст + графика) достаточно большого объема (~50 Мб) в одном файле.
Желательно, чтобы это был общедоступный формат типа XML, но чтобы его мог просмотреть неискушенный юзер.
То есть, данные в документе еще должны быть и оформлены красивым образом.
На ум приходят:
1) XML + XSL. Данные храним в XML, для отображения используем файл стилей. Минус — нет сжатия данных, вместо одного файла получаем два.
2) OpenDocument. Не работал с ним.
3) XPS файл.
4) PDF.
Нужно хранить некие данные (текст + графика) достаточно большого объема (~50 Мб) в одном файле.
Желательно, чтобы это был общедоступный формат типа XML, но чтобы его мог просмотреть неискушенный юзер.
То есть, данные в документе еще должны быть и оформлены красивым образом.
На ум приходят:
1) XML + XSL. Данные храним в XML, для отображения используем файл стилей. Минус — нет сжатия данных, вместо одного файла получаем два.
2) OpenDocument. Не работал с ним.
3) XPS файл.
4) PDF.
четверг, 25 марта 2010 г.
DirectMapTableModel
От DirectMap легко породить модель для представления данных.
DirectMapTableModel - представляет простую таблицу из 2-х колонок.
В первой колонке - ключи мапа, во второй - значения.
Это нечто вроде QStringListModel, только с двумя колонками вместо одной.
DirectMapTableModel - представляет простую таблицу из 2-х колонок.
В первой колонке - ключи мапа, во второй - значения.
Это нечто вроде QStringListModel, только с двумя колонками вместо одной.
понедельник, 1 марта 2010 г.
Qt баг
Под виндой с любой Qt, вплоть до последней, есть такой косяк с тулбаром.
Нужно: QMainWindow с тулбаром. Кнопка на тулбаре должна что-нибудь делать, желательно показывать некий диалог. Диалог должен закрываться по Esc.
Делаем: Быстро быстро клацаем по кнопке тулбара и тут же жмем Esc, закрывая тем самым диалог. На определенной итерации мы увидем, что кнопку тулбара залипла. Так, как будто у нее стоит статус Checkable.
Это легко проверить с Assistant'ом. Вызываем печать через тулбар и отменяем ее по Esc.
Итог: Весьма неприятно. На Qt и так полно нападок от нативщиков, и тут этот очевидный баг.
Нужно: QMainWindow с тулбаром. Кнопка на тулбаре должна что-нибудь делать, желательно показывать некий диалог. Диалог должен закрываться по Esc.
Делаем: Быстро быстро клацаем по кнопке тулбара и тут же жмем Esc, закрывая тем самым диалог. На определенной итерации мы увидем, что кнопку тулбара залипла. Так, как будто у нее стоит статус Checkable.
Это легко проверить с Assistant'ом. Вызываем печать через тулбар и отменяем ее по Esc.
Итог: Весьма неприятно. На Qt и так полно нападок от нативщиков, и тут этот очевидный баг.
Rotated Label
Компонента "Вращаемая надпись" - QLabel, который может быть повернут на любой угол. Стандартными Qt выми средствами этого не сделать, поэтому нужно изобретать велосипед.
Сначала мой велосипед. Здесь используется отрисовка текста QPainter'ом.
И другой велосипед. От shapoclak.
Здесь товарищ подошел с более интересной стороны
Сначала мой велосипед. Здесь используется отрисовка текста QPainter'ом.
И другой велосипед. От shapoclak.
Здесь товарищ подошел с более интересной стороны
В качестве девайса отрисовки виджета используется QPixmap. А сам QPixmap после любых манипуляций уже отрисовывается в любом другом месте. Подход хорош тем, что весь функционал QLabel остается.
суббота, 27 февраля 2010 г.
AbstractDateEdit - замена QDateEdit
QDateEdit - компонент для редактирования даты в Qt не умеет задавать пустую дату. Как это ни пародоксально. Пустая дата для него означает 01.01.2000.
Qt сообщество по этому поводу неоднократно сокрушалось и продолжало грызть кактус.
Результат моих грызений - собственный компонент AbstractDateEdit. Он обозван абстрактным, т.к. от него я планирую создать компоненты для работы с другими исчислениями даты. Но этот компонент ни фига не абстрактный а самый обычный, работающий с григорианским счислением. Имеет выпадающий календарик и прочие прелести.
Качать здесь .
Qt сообщество по этому поводу неоднократно сокрушалось и продолжало грызть кактус.
Результат моих грызений - собственный компонент AbstractDateEdit. Он обозван абстрактным, т.к. от него я планирую создать компоненты для работы с другими исчислениями даты. Но этот компонент ни фига не абстрактный а самый обычный, работающий с григорианским счислением. Имеет выпадающий календарик и прочие прелести.
Качать здесь .
Узнаем свой IP под Qt
В файле проекта подключаем QT += network
Используем.
Используем.
#include <QNetworkInterface>
QString localIP()
{
QString locIP;
QList<QHostAddress> addr = QNetworkInterface::allAddresses();
locIP = addr.first().toString();
return locIP;
}
* This source code was highlighted with Source Code Highlighter.
пятница, 26 февраля 2010 г.
AuthUnit - модуль авторизации
Добавил простенький модуль авторизации на Qt.
Функции модуля:
Авторизация пользователя и добавление нового с разграничением прав.
Модуль использует QSQLite. Требуемые модули Qt : QtSql, QtXml.
Пароли хэшируются MD5 и хранятся в конфигурационном файле config.xml.
При отсутствии конф. файла или повреждении его структуры модуль не проводит авторизацию.
Скачать можно здесь.
В архиве файл проекта .pri. Там же есть пример использования.
Использовать крайне просто. Нужно прицепить файл проекта к своему проекту вписав в него строчку include(AuthUnit/AuthUnit.pri)
После этого использовать
Функции модуля:
Авторизация пользователя и добавление нового с разграничением прав.
Модуль использует QSQLite. Требуемые модули Qt : QtSql, QtXml.
Пароли хэшируются MD5 и хранятся в конфигурационном файле config.xml.
При отсутствии конф. файла или повреждении его структуры модуль не проводит авторизацию.
Скачать можно здесь.
В архиве файл проекта .pri. Там же есть пример использования.
Использовать крайне просто. Нужно прицепить файл проекта к своему проекту вписав в него строчку include(AuthUnit/AuthUnit.pri)
После этого использовать
AuthUnit au;
if (au.exec() != QDialog::Accepted)
{
isAuthorized = false;
close();
return;
}
else
{
isAuthorized = true;
UserLogon user = au.logon();
}
* This source code was highlighted with Source Code Highlighter.
Используется структура UserLogon.struct UserLogon
{
QString name;
QString permission;
};
* This source code was highlighted with Source Code Highlighter.
DirectMap, оператор склейки
Расширим DirectMap оператором добавления.
template <class Key, class Value>
void DirectMap<Key, Value>::operator<<(const DirectMap<Key, Value> & right)
{
foreach (QString key, right.keys())
{
append(key, right[key]);
}
}
* This source code was highlighted with Source Code Highlighter.
четверг, 25 февраля 2010 г.
DirectMap - упорядоченный map
Недостаток ассоциативного массива QMap в том, что в нем ключи упорядочиваются. Т.е. если я добавлю в QMap" Key2", "Key1", то на выходе получу, сюрприз, "Key1", "Key2". Ключи будут отсортированы.
Такое поведение честно говоря подзае..ло, а альтернативы в Qt нету.
В качестве альтернативы они предлагают использовать QList<QPair <>>. Крайне громоздкая структура.
Наконец я решил сделать класс с удобством пользования как у QMap и с функционалом как у QList, т.е. без автоматического упорядочивания по ключам.
Начнем пожалуй.
Такое поведение честно говоря подзае..ло, а альтернативы в Qt нету.
В качестве альтернативы они предлагают использовать QList
Наконец я решил сделать класс с удобством пользования как у QMap и с функционалом как у QList, т.е. без автоматического упорядочивания по ключам.
Начнем пожалуй.
среда, 24 февраля 2010 г.
Qt и zip архивирование
Архивирование в Qt представлено методами qCompress() qUnCompress(). Они сожмут/разожмут некую последовательность байт, но обо всем остальном (запись в файл, сохранение структуры директорий, запись комментария и проч.) придется позаботиться тебе.
Поэтому для Qt написано много пакетов для работы с архивами.
Я лично предпочитаю The OSDaB Project.
http://code.google.com/p/osdab/source/browse/trunk/OSDaB-Zip
Meet a couple of pure-Qt/C++ classes capable of handling PKZIP 2.0 compatible zip archives.
Чтобы им пользоваться Qt должна быть собрана с поддержкой zlib. Само использование крайне легко, в примерах все описано.
Я же расскажу о неком досадном баге в этом пакете.
Я не буду углубляться в формат zip файла, он довольно сложен, главное вот это
Правки, которые пришлось сделать, располагаются в файле unzip.cpp
Магический параметр UNZIP_EOCD_SIZE установлен равным 18
В функции
Поэтому для Qt написано много пакетов для работы с архивами.
Я лично предпочитаю The OSDaB Project.
http://code.google.com/p/osdab/source/browse/trunk/OSDaB-Zip
Meet a couple of pure-Qt/C++ classes capable of handling PKZIP 2.0 compatible zip archives.
Чтобы им пользоваться Qt должна быть собрана с поддержкой zlib. Само использование крайне легко, в примерах все описано.
Я же расскажу о неком досадном баге в этом пакете.
Я не буду углубляться в формат zip файла, он довольно сложен, главное вот это
Файл ZIP определяется наличием центрального каталога, который расположен в конце файла. В каталоге хранится список имен записей (файлов или каталогов), которые хранятся в файле ZIP, наряду с другими метаданными о входе и смещении в файле ZIP, указывающими на фактическое расположение сжатых данных.Проблема в том, что OSDaB считает что центральный каталог начинается начинается с минус 22 байта от конца архива. Т.е. он отступает 22 байта от конца файла архива и ищет там начало секции Центрального Каталога. Секция ЦК начинается с байт PK56. Так вот если он ее там не найдет, то начинается двигаться в начало файла но с шагом кратным 22. Для большинства архивов это работает. По ходу работы пришлось столкнуться с архивами у которых ЦК начинается вовсле не с -22 байта, а с 18 или 21. Поэтому проект пришлось подправить чтобы начинал поиск секции ЦК с 18 и шагал по 1 байту в начало. Это понижает скорость работы архиватора, но по крайней мере нужные мне архивы стали нормально читаться.
Правки, которые пришлось сделать, располагаются в файле unzip.cpp
Магический параметр UNZIP_EOCD_SIZE установлен равным 18
В функции
UnZip::ErrorCode UnzipPrivate::seekToCentralDirectory()
закоментарена строчка //offset -= UNZIP_EOCD_SIZE;
чтобы шаг был 1 байт. Кроме тогоoffset -= 1 /*UNZIP_EOCD_SIZE*/;
И ввел дополнительную проверкуif (offset > length)
offset = getSULong((const unsigned char*) buffer1, UNZIP_EOCD_OFF_CDOFF + 4);
Определив функцию getSULong
quint32 UnzipPrivate::getSULong(const unsigned char* data, quint32 offset) const
{
quint32 res = (quint32) data[offset];
res |= (((quint32)data[offset+1]) << 8);
return res;
}
* This source code was highlighted with Source Code Highlighter.
суббота, 20 февраля 2010 г.
Цытата
Плакал от цитаты. Насколько верно....
Eсли кучку программистов оставить на некоторое время без присмотра (читай без управления), они очень быстро скатываются в производство не продукта, а прикольных фиговин для самих себя. Как правило, эти фиговины остальным людям не интересны, поэтому программистам перестают давать за них деньги.Прикольные фиговины для себя - моя слабость ))
вторник, 16 февраля 2010 г.
Криптография под Qt выпуск 4
Набор библиотек для переноса QCA:
plugins\crypto\qca-ossl2.dll 196 Kb
qca2.dll 749 Kb
libeay32.dll 1 Mb
ssleay32.dll 200 Kb
Получается довесок в пару мегабайт за возможность шифровать/дешифровать.
plugins\crypto\qca-ossl2.dll 196 Kb
qca2.dll 749 Kb
libeay32.dll 1 Mb
ssleay32.dll 200 Kb
Получается довесок в пару мегабайт за возможность шифровать/дешифровать.
Криптография под Qt выпуск 3
Криптография с симметричным ключом вполне заработала. Ширфемся по алгоритму AES.
Чтобы расшифроваться нужно у чипера поменять
В следующем выпуске рассмотрим какие библиотеки нужны для переноса OpenSSL на чистую машину.
Чтобы расшифроваться нужно у чипера поменять
QCA::Encode на
QCA::Decode.
QString encrypt(const QString & strToEnrypt)
{
//инициализация
QCA::Initializer init;
//переводим строку в засекречивамый массив
QCA::SecureArray arg = QVariant(strToEnrypt).toByteArray();
QString res;
// проверка что поддерживаем алгоритм AES128 testing
if (QCA::isSupported("aes128-cbc-pkcs7"))
{
QString sKey = "aes128-cbc-pkcs7-sn93-sh21-jks-12";
//некоторые преобразования над ключом
//по идее должны затруднять реверсинг
QStringList lst = sKey.split("-");
lst = lst.replaceInStrings("c", "s");
lst.removeAt(0);
lst.removeAt(5);
QString sKeyCh = lst.join(".");
//создаем ключ
QCA::SymmetricKey key(QVariant(lst.join(".")).toByteArray());
//Создать случайный инициализирующий вектор
//вам нужно это значение чтобы расшифровать результат шифра
//но это нужно хранить в секрете в отличие от ключа
QCA::InitializationVector iv(QVariant(lst.join(">")).toByteArray());
//содать 128 битный AES шифр объект используя CBC режим
QCA::Cipher cipher(QString("aes128"), QCA::Cipher::CBC,
//использовать отступ по умолчанию который эквивалентен PKCS7 для CBC
QCA::Cipher::DefaultPadding,
// этот объект будет зашифрован
QCA::Encode,
key, iv);
QCA::SecureArray u = cipher.update(arg);
if (!cipher.ok())
{
return res;
}
QCA::SecureArray f = cipher.final();
if (!cipher.ok())
{
return res;
}
res = QString(f.data());
}
return res;
}
* This source code was highlighted with Source Code Highlighter.
В следующем выпуске рассмотрим какие библиотеки нужны для переноса OpenSSL на чистую машину.
понедельник, 15 февраля 2010 г.
Криптография под Qt выпуск 2
Как оказалось, чтобы собрать нормальную дебаг версию надо было указать ключ --debug-and-release для configure.exe.
Но это еще не все.
По умолчанию QCA поддерживает только алгоритмы SHA1 и MD5. Чтобы получить остальное нужно ставить дополнительный плагин qca-ossl-2.0.0-beta3.tar.bz2.
Установка его дает нам такой комбайн поддерживаемых алгоритмов: TLS, CMS, X.509, RSA, DSA, Diffie-Hellman, PKCS#7, PKCS#12, SHA0, SHA1, SHA224, SHA256, SHA384, SHA512, MD2, MD4, MD5, RIPEMD160, Blowfish, DES, 3DES, AES128, AES192, AES256, CAST5, HMAC(SHA1, MD5, RIPEMD160), PBKDF1(MD2, SHA1), PBKDF2(SHA1).
Этот плагин в свою очередь зависит от OpenSSL версии не ниже 0.9.6
Взять его можно здесь openssl-0.9.8l
После чего конфигуряется командой
> perl Configure VC-WIN32 --prefix=c:/some/openssl/dir
Затем
> ms\do_ms
И
> nmake -f ms\ntdll.mak
> nmake -f ms\ntdll.mak install
После установки OpenSSL нужно сплясать еще один танец с бубном. Это касатся уже установки плагина qca-ossl.
В Папке %QTDIR% \mkspecs\features нужно создать файл winlocal.prf со строчкой WINLOCAL_PREFIX = D:/OpenSSL
То есть, указать путь до собранной OpenSSL.
В ходе сборки плагина у меня выскакивала ошибка, что де не найден OBJ_whirlpool. Эта переменная определена в OpenSSL, и управляет включением алгоритма Whirlpool — криптографическая хеш-функция.
Однако плагин в упор не видит исходного кода алгоритма и вылетает. Пришлось в коде плагина убрать упоминания о Whirlpool.
В итоге плагин qca-ossl2.dll все таки собрался.
Копируем его в %QTDIR%\plugins\crypto.
Завтра будем пробовать. По крайней мере if(QCA::isSupported("aes128-cbc-pkcs7")) стало возвращать true.
Но это еще не все.
По умолчанию QCA поддерживает только алгоритмы SHA1 и MD5. Чтобы получить остальное нужно ставить дополнительный плагин qca-ossl-2.0.0-beta3.tar.bz2.
Установка его дает нам такой комбайн поддерживаемых алгоритмов: TLS, CMS, X.509, RSA, DSA, Diffie-Hellman, PKCS#7, PKCS#12, SHA0, SHA1, SHA224, SHA256, SHA384, SHA512, MD2, MD4, MD5, RIPEMD160, Blowfish, DES, 3DES, AES128, AES192, AES256, CAST5, HMAC(SHA1, MD5, RIPEMD160), PBKDF1(MD2, SHA1), PBKDF2(SHA1).
Этот плагин в свою очередь зависит от OpenSSL версии не ниже 0.9.6
Взять его можно здесь openssl-0.9.8l
OpenSSL — криптографический пакет с открытым исходным кодом для работы с SSL/TLS. Позволяет создавать ключи RSA, DH, DSA и сертификаты X.509, подписывать их, формировать CSR и CRT. Также имеется возможность шифрования данных и тестирования SSL/TLS соединений.Чтобы собрать OpenSSL нужен Perl. Пришлось поставить Strawberry Perl.
OpenSSL поддерживает разные алгоритмы шифрования и хеширования:
Поддержка алгоритмов ГОСТ появилась в версии 1.0.0, в данный момент находящейся в стадии бета-тестирования.
- Симметричные
- Blowfish, Camellia, DES, RC2, RC4, RC5, IDEA, AES, ГОСТ 28147-89
- Хеш-функции
- MD5, MD2, SHA, MDC-2, ГОСТ Р 34.11-94
- Асимметричные
- RSA, DSA, Diffie-Hellman key exchange, ГОСТ Р 34.10-2001, ГОСТ Р 34.10-94
После чего конфигуряется командой
> perl Configure VC-WIN32 --prefix=c:/some/openssl/dir
Затем
> ms\do_ms
И
> nmake -f ms\ntdll.mak
> nmake -f ms\ntdll.mak install
После установки OpenSSL нужно сплясать еще один танец с бубном. Это касатся уже установки плагина qca-ossl.
В Папке %QTDIR% \mkspecs\features нужно создать файл winlocal.prf со строчкой WINLOCAL_PREFIX = D:/OpenSSL
То есть, указать путь до собранной OpenSSL.
В ходе сборки плагина у меня выскакивала ошибка, что де не найден OBJ_whirlpool. Эта переменная определена в OpenSSL, и управляет включением алгоритма Whirlpool — криптографическая хеш-функция.
Однако плагин в упор не видит исходного кода алгоритма и вылетает. Пришлось в коде плагина убрать упоминания о Whirlpool.
В итоге плагин qca-ossl2.dll все таки собрался.
Копируем его в %QTDIR%\plugins\crypto.
Завтра будем пробовать. По крайней мере if(QCA::isSupported("aes128-cbc-pkcs7")) стало возвращать true.
Конвертация QString в LPTSTR
LPTSTR это 32-битный указатель на Unicode строку.
Возвращать указатель из функции не совсем корректно и, например, у нас на фирме запрещено писать функции, возвращающие указатели. Т.к. программист в такой функции выделяет память и возвращает указатель на нее. А об удалении должен заботиться прикладной программист, а он может легко это забыть и получим утечку ресурсов.
Поэтому я приведу кусок кода, конвертирующий QString в LPTSTR без этих тонкостей. Кому надо напишут нужную функцию.
Возвращать указатель из функции не совсем корректно и, например, у нас на фирме запрещено писать функции, возвращающие указатели. Т.к. программист в такой функции выделяет память и возвращает указатель на нее. А об удалении должен заботиться прикладной программист, а он может легко это забыть и получим утечку ресурсов.
Поэтому я приведу кусок кода, конвертирующий QString в LPTSTR без этих тонкостей. Кому надо напишут нужную функцию.
QString str = "String";
WCHAR * wStr = new WCHAR[str.length() + 1];
MultiByteToWideChar( 0, 0, str.toAscii().data(), str.length(), wStr, str.length());
wStr[str.length()] = '\0';
LPTSTR lpszStr = wStr;
delete [] wStr;
wStr = 0;
* This source code was highlighted with Source Code Highlighter.
пятница, 12 февраля 2010 г.
Криптография под Qt выпуск 1
В стандартной поставке Qt совсем немного средств для криптографии. По сути все ограничивается одним классом QCryptographicHash.
Этот класс может получать хэш от некоторых данных, представленных в QByteArray, используя алгоритмы Md4, Md5, Sha.
Ну а что такое хэш? Хэш это необратимая последовательность символов, зная которую исходные данные никак не получить. Это удобно для хранения паролей. Хранишь хэш пароля и сравниваешь хэши паролей вместо них самих.
Однако в ряде случаев этого бывает недостаточно. И хочется иметь нормальное обратимое шифрование с ключами.
Порыскал в инете на эту тему, нашел пакет Qt Cryptographic Architecture (QCA).
Обитает он на:
http://delta.affinix.com/qca/
Скачиваем, разворачиваем в %QTDIR%/src/3rdparty/
Далее, configure.exe & nmake & installwin.exe
В результате оно установит Qt feature, т.е. фишку Qt.
Теперь в файле проекта можно написать CONFIG += crypto
И использовать в коде #include <QtCrypto>
На этом пока мое знакомство с QCA закончилось. В дебаге оно почему то не может найти либу qcad.lib, в релизе собирается нормально. Будем разбираться дальше.
Upd:
Для дебага пришлось поправить строку в %QTDIR%/mkspecs/features/crypto.prf
Вместо windows:LINKAGE = -lqcad
написал windows:LINKAGE = -lqca2
Этот класс может получать хэш от некоторых данных, представленных в QByteArray, используя алгоритмы Md4, Md5, Sha.
Ну а что такое хэш? Хэш это необратимая последовательность символов, зная которую исходные данные никак не получить. Это удобно для хранения паролей. Хранишь хэш пароля и сравниваешь хэши паролей вместо них самих.
Однако в ряде случаев этого бывает недостаточно. И хочется иметь нормальное обратимое шифрование с ключами.
Порыскал в инете на эту тему, нашел пакет Qt Cryptographic Architecture (QCA).
Обитает он на:
http://delta.affinix.com/qca/
Скачиваем, разворачиваем в %QTDIR%/src/3rdparty/
Далее, configure.exe & nmake & installwin.exe
В результате оно установит Qt feature, т.е. фишку Qt.
Теперь в файле проекта можно написать CONFIG += crypto
И использовать в коде #include <QtCrypto>
На этом пока мое знакомство с QCA закончилось. В дебаге оно почему то не может найти либу qcad.lib, в релизе собирается нормально. Будем разбираться дальше.
Upd:
Для дебага пришлось поправить строку в %QTDIR%/mkspecs/features/crypto.prf
Вместо windows:LINKAGE = -lqcad
написал windows:LINKAGE = -lqca2
Поднимаем привилегии до админа под Windows XP
Понадобилось мне как-то сделать так, чтобы моя программа, будучи запущенной под ограниченным пользователем, могла сама себе поднимать привилегии до администраторских.
Исходные условия: Windows XP, известные логин и пароль админа.
Цель: Научить программу поднимать себе привилегии.
Все оказалось достаточно просто:
Поэтому, перед тем как вызвать диалог открытия/сохранения файла - верните программе юзерский уровень и поднимите его обратно после работы с диалогом.
Или давайте админский уровень своей программе только на очень короткий срок и немедленно возвращайте его обратно, как только надобность в нем отпадет.
Исходные условия: Windows XP, известные логин и пароль админа.
Цель: Научить программу поднимать себе привилегии.
Все оказалось достаточно просто:
#include "windows.h"
//Поднять права до админских
bool logonAsAdmin()
{
LPTSTR lpszUsername = L"Admin"; // логин админа
LPTSTR lpszDomain = NULL; // домен
LPTSTR lpszPassword = L"passw"; // пароль админа
HANDLE hToken; //маркер доступа (токен)
//Получаем токен админа
if (!LogonUser(lpszUsername, lpszDomain, lpszPassword, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, &hToken))
return false;
//Прикидываемся админом
if (!ImpersonateLoggedOnUser(hToken))
return false;
return true;
}
* This source code was highlighted with Source Code Highlighter.
Но тут надо помнить о дыре, которую дает данный код. Дело в том, что в программе может быть код, дающий пользователю доступ к файловой системе с правами админа. Например, если в вашей программе есть диалог открытия файла и вы дали своей программе админский доступ, то такой доступ получит и пользователь программы.Поэтому, перед тем как вызвать диалог открытия/сохранения файла - верните программе юзерский уровень и поднимите его обратно после работы с диалогом.
Или давайте админский уровень своей программе только на очень короткий срок и немедленно возвращайте его обратно, как только надобность в нем отпадет.
среда, 27 января 2010 г.
Продолжаем удалять файлы и каталоги
Функция рекурсивного удаления папок не работает если в папке есть файлы только для чтения.
Функция QFile::remove() при попытке удалить такой файл возвращает false. Чтобы этого избежать нужно выставлять права для таких файлов. В Qt для этого есть функция
bool QFile::setPermissions ( const QString & fileName, Permissions permissions ) [static]
Таким образом окончательный вид функции удаления каталога имеет вид:
Функция QFile::remove() при попытке удалить такой файл возвращает false. Чтобы этого избежать нужно выставлять права для таких файлов. В Qt для этого есть функция
bool QFile::setPermissions ( const QString & fileName, Permissions permissions ) [static]
Таким образом окончательный вид функции удаления каталога имеет вид:
четверг, 21 января 2010 г.
Очистка каталога
void cleanFolder(const QString & folder)
{
QDir dir(folder);
//Получаем список файлов
QStringList lstFiles = dir.entryList(QDir::Files);
//Удаляем файлы
foreach (QString entry, lstFiles)
{
QString entryAbsPath = dir.absolutePath() + "/" + entry;
QFile::remove(entryAbsPath);
}
}
* This source code was highlighted with Source Code Highlighter.
вторник, 19 января 2010 г.
Подсветка кода для блога
Изначально я планировал в этом блоге писать о программировании на Qt. Однако сейчас на блоге больше всего постов о покере, Москве, пиве и прочем непотребстве.
Объясняю в чем секрет - отсутствие толковой подсветки кода. Те куски кода, что я помещал в блог имели столь ужасное форматирование и подсветку, что без содрогания читать программу просто невозможно. Я перепробовал множество подсветчиков, однако у всех были недостатки - кто-то по глупому делает подсветку, кто-то мутит с CSS, что вызывает трудности со вставкой кода.
Наконец я нашел приличный подсветчик: http://source.virtser.net
Он не использует CSS и делает подсветку аналогично Visual Studio.
Вот пример сгенеренного им кода.
На мой взгляд - лучшее решение для вставки кода в блог.
Объясняю в чем секрет - отсутствие толковой подсветки кода. Те куски кода, что я помещал в блог имели столь ужасное форматирование и подсветку, что без содрогания читать программу просто невозможно. Я перепробовал множество подсветчиков, однако у всех были недостатки - кто-то по глупому делает подсветку, кто-то мутит с CSS, что вызывает трудности со вставкой кода.
Наконец я нашел приличный подсветчик: http://source.virtser.net
Он не использует CSS и делает подсветку аналогично Visual Studio.
Вот пример сгенеренного им кода.
ApPhotoRobot::ApPhotoRobot(QWidget * parent )
: DirSelecter(tr("Applications - PhotoRobot"), parent)
{
lstlblPath.at(0)->setText(tr("Folder of Bars PhotoRobot"));
lstlblName.at(0)->setText(tr("Executable name of Bars PhotoRobot"));
leOut = new QLineEdit(this);
QLabel * lblOut = new QLabel(tr("Output folder for Bars Photorobot"), this);
QToolButton * btnBars = new QToolButton(this);
btnBars->setFixedSize(20, 20);
btnBars->setText("...");
connect(btnBars, SIGNAL(clicked()), this, SLOT(browseDir()));
mapBtnEdt[btnBars] = leOut;
grid->addItem(new QSpacerItem(1, 10, QSizePolicy::Fixed, QSizePolicy::Fixed), 5, 0);
grid->addWidget(lblOut, 6, 0, 1, 2);
grid->addWidget(leOut, 7, 0);
grid->addWidget(btnBars, 7, 1);
grid->setRowStretch(8, 1);
}
* This source code was highlighted with Source Code Highlighter.
На мой взгляд - лучшее решение для вставки кода в блог.
Подписаться на:
Сообщения (Atom)