04 декабря 2010

Oracle, qt, out параметры

Путем некоторого количества грубой силы я добился от оракла выходных параметров. Итак, оказывается, чтобы это эта база данных вернула нам некоторый параметр, в моем случае это выглядит так update test set name='michael' returning id, name into :id, :name, мы должны заранее выделить место под возвращаемые переменные. Вот код для Qt, показывающий выше сказанное:
QSqlQuery update;
update.prepare("update test set name='michael' returning id, name into :id, :name");
update.bindValue("id", QString(1024, QChar()), QSql::Out);
update.bindValue("name", QString(1024, QChar()), QSql::Out);
update.exec();
int id = update.boundValues().value("id").toInt();
QString name = update.boundValues().value("name").toString();

14 ноября 2010

Находясь в обожании postgresql

На данный момент нахожусь в поисках python-postgresql драйвера, и случайно заглянул на wiki postgresql.
В моем проекте есть функция автоматической генерации расписаний в соответствии с некоторыми условиями (диапазон, шаг). Но она пока несколько сложна для объяснения базовых принципов генерации списка дат. Лучше использую более простой пример. Для некоторого планирования существует таблица, содержащая список нерабочих дней предприятия. Данная таблица может заполняться как вручную, так и автоматически. Набросок "по-быстрому" функции заполнения таблицы воскресеньями (Никогда не повторяйте этого дома!). Лучше не вчитывайтесь, просто увидте цикл, и поймите мою ошибку. В целом функция генерирует на 700 дней вперед от сегодня.

CREATE OR REPLACE FUNCTION fill_holidays()
  RETURNS void AS
$BODY$
declare
currentDay date = current_date;
begin
<<for_loop>>
FOR i IN  1..700 by 1 LOOP
  if (date_part('dow', currentDay) = 0 and not exists (select _day from catalog_holidays where _day = currentDay)) then
  insert into catalog_holidays(_date) values (currentDay);
 end if;
 currentDay = currentDay + 1;
 raise notice '%',currentDay;
END LOOP for_loop;
return;
end;
 $BODY$
  LANGUAGE plpgsql;
COMMENT ON FUNCTION fill_holidays() IS 'Заполнить выходными';


Так делает среднестатистический c++ программист. А вот как надо делать. Цель та же, генерация на 700 дней вперед. Смотрите внимательно, а то вы можете случайно пропустить строчку, которая все это делает:

insert into catalog_holidays(_date) (select a::date from generate_series(current_timestamp, current_timestamp + '700 days', '1 day') a where extract('isodow' from a) = 7);
И не подумайте, что пытаюсь вас надуть неиспользованием хранимой процедуры и говорю о сокращении кода. В первом случае я использовал хранимую процедуру, потому что анонимных блоков в 8.4 еще не было. Во втором же случае вы видите, что хранимая процедура неуместна за отсутствием вспомогательной переменной и цикла.

А теперь внимание...сделайте для меня точно эту же операцию на oracle. А когда сделаете, подумайте, на что вы тратите свои деньги и время. Сравните приведение типов в этих двух СУБД, а еще сравните работу со датами/временем, пока я не сделал это за вас. Иногда мне кажеться, что одни люди занимаются "финансово-денежными операциями", а другие искусством создания программ. Но это уже совсем другая история...
Список литературы:
Scott Bailey 'Artacus'. Date Generator /  Postgresql Wiki

P.S. Мне действительно очень стыдно за первый вариант функции.

11 ноября 2010

А знаете ли Вы, что....

......можно сделать Qt прокси модель по-быстрому?
Для начала поищите такие стратегические костыли для c++, как доступ к приватным членам. Затем возьмите QModelIndex() и создайте свой. Только вместо слова private употребите слово public.
Затем унаследуйте QAbstractProxyModel и переопределите mapToSource, mapFromSource.
В них сделайте reintepret_cast для индексов. И поменяйте нужному индексу нужную модель.

13 октября 2010

Qt и oracle.

Значит есть в postgresql такая возможность как returning clause. Если сделать update, insert или delete, то можно получить значения строки используя конструкцию
returning [column1 [,column2]] | *
Для клиентского приложения, и для Qt в частности, это будет выглядеть так, будто команда вернула некоторый recordset.
Но не таким путем решается задача в oracle. В oracle необходимо конструировать следующее выражение:
returning column1 into :colunm1outvar
Затем производить связывание out переменной QSqlQuery::bindValue(":column1outvar", QVariant(QSqlField::type()), QtSql::Out);
А после QSqlQuery::exec(), получить связанные значения.
Причем то, что я написал только одну переменную не ошибка. На большем количестве oracle выдает сообщение о несвязанных переменных.
Возможно это ошибка QtSqlOci плагина, возможно нет. Вывод который мне хочеться сделать, хотя рано мне еще выводы делать: oracle большая самодостаточная система, к которой сторонние приложения не допускаются, хотите автоматизацию бизнес процесса, делайте только с помощью продуктов oracle, никаких сторонних библиотек; ну а если хочеться и мощность (триггеры, функции) и простоту, то тогда выбор в пользу postgresql.

27 сентября 2010

From Qt to GTK

Итак, в связи с некоторыми убеждениями я начал поиски вида "GTK vs Qt 2010".
ссылка
В данном сообщении Johan Thelin рассказывает о том, как можно сделать GTK из Qt. Хотя нет, наоборот, Qt из GTK.
Идем далее:
ссылка
А вот здесь San Celettu делает вывод о том, что GTK более выгодный инструмент для использования, чем Qt, основываясь на легковесности первого.
ссылка
Обсуждение Qt vs PyGtk for postgresql frontend

16 сентября 2010

с++ vs python

Хотелось бы привести слова Пола Грэма в качестве маленького сравнения c++ и python:
За те годы, что я проработал в Viaweb, я прочитал множество объявлений о найме на работу. Примерно каждый месяц появлялся новый конкурент. Первое, что я делал после того, как проверял, доступна ли онлайновая демонстрация работы их программы, — смотрел список их вакансий. Через пару лет я научился отличать опасных конкурентов от неопасных. Чем больше отдавало IT-мэйнстримом от описания требуемых кандидатур, тем менее опасна была компания. Самыми безопасными были те, кому требовались специалисты по Oracle. О таких не стоило беспокоиться. Также мы были спокойны, если требовались разработчики на C++ или Java.
Если требовались программисты на Perl или Python, это уже было слегка пугающе — это значило, что компанией или, по крайней мере, ее технической частью заправляли настоящие хакеры. Если бы я когда-нибудь увидел объявление о найме на работу Lisp-хакеров, я бы обеспокоился не на шутку.

06 сентября 2010

Понравились цвета

Нужно запомнить, чтобы везде использовать.

24 августа 2010

Qt ресурсы в статической библиотеке...

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

17 августа 2010

Re-packaging a deb package

Remove depen of qt libraries for virtual box
dpkg -e virtualbox-3.2_3.2.8-64453~Ubuntu~karmic_amd64.deb 
cd DEBIAN/
nano control 
# remove all depen for qt
# Ctrl+O
# Ctrl+X
tar -czvf control.tar.gz *
mv control.tar.gz ..
cd ..
ar r virtualbox-3.2_3.2.8-64453~Ubuntu~karmic_amd64.deb control.tar.gz

25 июля 2010

Opera 10.60

Броузер с 15-ти летней историей ни в какую не хочет авторизировать меня по данной ссылке: https://www.google.com/accounts/ServiceLogin.... Кроме того покопавшись в могучем многомиллиардном интернете, все что я нашел, это: "google не поддерживает оперу", "опера не поддерживает google".
Грустно. P.S. Но впринципе щелкая по разным web auth box'ам в блог я-таки попадаю.

16 июля 2010

Использование QtScriptGenerator

QtScriptGenerator (далее - Кугенератор) позволяет сделать доступным почти любой Qt или Qt-подобный класс в среде Qt Script.

Маленькие хитрости

Если какой-нибудь из high-level qt плагинов ни в какую не хочет загружаться, то:
1. Возмите его имя.
2. Передайте его в конструктор объекта QLibrary.
3. Вызовите метод load вышеназванного объекта.
4. И если вышеназванный метод не принес положительного результата, выведите в qDebug() результат метода errorString объекта типа QLibrary.

03 июля 2010

Qt and get current user name

Used as qt script function wrapper:
// Crosplatform getUserName function
#ifdef Q_WS_WIN
#include <windows.h>
#include <lmcons.h>
#elif defined Q_WS_X11
#include <pwd.h>
#endif //#ifdef Q_WS_WIN

QScriptValue getLoginWrapper(QScriptContext* context, QScriptEngine* engine)
{
  QString userName;
#ifdef Q_WS_WIN
  WCHAR* lpszSystemInfo; // pointer to system information
  DWORD cchBuff = 256; // size of user name
  WCHAR tchBuffer[UNLEN + 1]; // buffer for expanded string

  lpszSystemInfo = tchBuffer;

  // Get and display the user name.
  GetUserNameW(lpszSystemInfo, &cchBuff);

  //Unicode string needs to be converted
  userName = QString::fromWCharArray(lpszSystemInfo);
#elif defined Q_WS_X11
  register struct passwd *pw;
  pw = getpwuid(getuid());
  if (pw)
  userName = pw->pw_name;
#endif //#ifdef Q_WS_WIN

  return userName;
}

01 июля 2010

Иконка приложения в win среде.

Продолжаем тему. С изобретением иконок в дизайне их начали засовывать в самые труднодоступные места. Засунем и мы иконку в исполняемый в win среде файл, чтобы любой "проводник" показывал нам не синюю рамку с тремя пуговицами.

30 июня 2010

Калькулятор в каждый QLineEdit? Легко.

Attention: Qt Script with bindings used.
Итак задача: пользователь вводит какой-либо результат в QLineEdit списывая его из какого-нибудь листочка. Однако если на листочке есть только исходные данные, но не вычислен результат? Поэтому мною был придуман виджет калькулятор, который работает с QLineEdit'ом имеющим фокус ввода. Пользователь вводит исходное выражение, а виджет вычисляет результат. Итак модифицированный код из прошлого сообщения моего блога:

29 июня 2010

Объект String в Qt Script и номер unicode символа

String.fromCharCode
СинтаксисString.fromCharCode(num1, ..., numN)

Аргументы
num1, ..., numN
последовательность чисел, представляющих собой коды Unicode-символов
Описание, примеры

Этот метод возвращает элементарную строку, а не объект типа String.

Так как fromCharCode - статический метод String, он всегда вызывается как String.fromCharCode().

Ссылка на первоисточник
Данная функция присутствует и в Qt Script. Пример использования:

String.fromCharCode(QLocale.system().decimalPoint())

Простая цифровая экранная клавиатура на Qt Script

Создание такой клавиатуры не составляет труда. Но я ее сделал на Qt Script в сочетании с Qt Script Bindings Generator. Я не правильно выражаюсь, вот как надо понимать словосочетание Qt Script Bindings Generator: "Qt Script плагины, осуществляющие доступ к почти все объектам Qt".

27 июня 2010

Добавляем QListView на QMenu

Добавляем с помощью спецаильно обученного класса QWidgetAction. QListView будет отображаться только на одном меню, куда он был впервые установлен.
QMenu *menu = new QMenu(0);
listView = new QListView(0);
QWidgetAction *wA;
wA = new QWidgetAction(this);
wA->setDefaultWidget(listView);
menu->addAction(wA);

26 июня 2010

Как "динамически" соединить сигнал с сигналом/слотом?

Обычно соединение происходит в виде: connect(obj1, SIGNAL(signal()), obj2, SLOT(slot())); Но такой код не сработает, если имя слота хранится в переменной. Для решения проблемы имитируем макросы SIGNAL и SLOT.

QString signal1 = QMetaObject::normalizedSignature("signal1( )");
QString signal2 = QMetaObject::normalizedSignature("signal2( )");
QString slot1 = QMetaObject::normalizedSignature("slot( )");
connect(obj1, QString("%1%2").arg(QSIGNAL_CODE).arg(signal1).toLatin1().data()
, obj2, QString("%1%2").arg(QSIGNAL_CODE).arg(signal2).toLatin1().data());
connect(obj1, QString("%1%2").arg(QSIGNAL_CODE).arg(signal2).toLatin1().data()
, obj3, QString("%1%2").arg(QSLOT_CODE).arg(slot1).toLatin1().data());

Стандартный делегат с возможностью дополнения.

Наследуемся от QStyledItemDelegate.
Заголовочный файл pgqueryitemdelegate.h
class PGQueryItemDelegate : public QStyledItemDelegate
{
  Q_OBJECT
  public:
  explicit PGQueryItemDelegate(QObject* parent = 0);

  QWidget* createEditor (QWidget* parent,
                         const QStyleOptionViewItem& option,
                         const QModelIndex& index ) const;

protected:
  virtual bool eventFilter(QObject *object, QEvent *event);
};
Файл реализации pgqueryitemdelegate.cpp
PGQueryItemDelegate::PGQueryItemDelegate(QObject* parent):QStyledItemDelegate(parent)
{
  setObjectName("pgQueryItemdelegate");
}

QWidget *PGQueryItemDelegate::createEditor(QWidget *parent,
                                           const QStyleOptionViewItem &option,
                                           const QModelIndex & index ) const
{
  QWidget *editor = QStyledItemDelegate::createEditor(parent, option, index);
  QLineEdit* lineEdit = qobject_cast(editor);
  if (lineEdit) {
    QMap<QString, int> values;
    QString itemData;
    int start = qMax(0, index.row() - 600);
    int end = qMin(index.model()->rowCount(index.parent()), index.row() + 600);
    for (int row = start; row < end; ++row) {
      itemData = index.model()->index(row, index.column(), index.parent()).data().toString();
      values.insert(itemData, index.row());
    }

    QCompleter* completer = new QCompleter(values.keys(), lineEdit);
    completer->setCompletionColumn(0);
    completer->setModelSorting(QCompleter::CaseSensitivelySortedModel);
    completer->setCompletionMode(QCompleter::InlineCompletion);
    lineEdit->setCompleter(completer);
    return lineEdit;
  }

  return editor;
}

bool PGQueryItemDelegate::eventFilter(QObject *object, QEvent *event)
{
  if (event->type() == QEvent::FocusIn) {
    QLineEdit *lineEdit = qobject_cast(object);
    if (lineEdit) {
      if (lineEdit->completer())
        lineEdit->completer()->setCompletionMode(QCompleter::PopupCompletion);
    }
  }
  if (event->type() == QEvent::FocusOut) {
    QLineEdit *lineEdit = qobject_cast(object);
    if (lineEdit) {
      QFocusEvent *focusEvent = static_cast(event);
      if (lineEdit->completer())
        if (qApp->activeWindow() == lineEdit->completer()->popup())
          return true;
    }
  }
  return QStyledItemDelegate::eventFilter(object, event);
}

Получить комментарий к pgsql объектам "по-быструхе"

Attention: используется Qt Script. 
Механизм комментариев в postgresql представляет собой очень такой упругий клапан: комментарий задать легче простого, получить его обратно "почти невозможно". Официальная postgres документация, рассказывает о 4 функциях. google.com на запрос "postgresql get object comment" отсылает к оф. документации.
Если у кого есть отточенный механизм, то он скорее всего выужен из исходного кода psql или pgAdmin. Мне туда лезть пока не хочеться, хватает дебрей Qt.

Итак отобрать обратно комментарий от собственно самой базы данных, к которой мы сейчас подключены:
var query = new QSqlQuery(database);
query.exec("select description from pg_shdescription join pg_database on objoid = oid and datname = current_database()");
query.next();
print(query.value(0));

Получить комментарий к таблице:
var tableName = "tableName";
var sqlQuery = new QSqlQuery(database);
sqlQuery.exec("select description from pg_description where objsubid = 0 and objoid = '%1'::regclass ".arg(tableName));
query.next();
print(sqlQuery.value(0));

Получить комментарий к столбцу:
var columnIndex = 1;
var tableName = "tableName";
var sqlQuery = new QSqlQuery(database);
sqlQuery.exec("select description from pg_description where objsubid = %2 and objoid = '%1'::regclass ".arg(tableName).arg(columnIndex));
query.next();
print(sqlQuery.value(0));

18 июня 2010

08 мая 2010

PostgeSQL записки #2 для QT Script

Еще один способ подписаться на RAISE [level] ... записки генерируемые на стороне PostgreSQL сервера. На этот раз я просто добавил динамическую загрузку libpq.

05 мая 2010

QSettings in Qt Script Environment

При использовании объекта типа QSettings в среде Qt Script существует одна проблема. Когда Вы устанавливаете какое-либо значение для какого-либо ключа, в объекте оно сохраняется в QVariant. После сохранения ключей и значений в файл или другое место они конвертируются/кодируются в значения типа QString. После загрузки значений из файла в объект, в объекте они хранятся в виде QString. А во время получения данных значений используя функцию QSettings::value они преобразовываются с помощью конвертирующих функций определенных в QVariant.

Говоря проще, при второй загрузке приложения, все ранее сохраненные настройки имеют тип QString.
Ну так вот сама проблема:
QVariant ковертирует строку "false" в bool false.
В среде Qt Script QSettings::value возвращает строку и данная строка если она не пустая конвертируется в true. Это значит, что в Qt Script данный код будет работать корректно только при первом запуске приложения:
var settings = new QSettings(this);
if (!settings.contains("key"))
  settings.setValue("key", false);
if (!settings.value("key"))
  print("key is false");
При последующих запусках приложения settings.value("key") будет возвращать строку "false" и Qt Script будет ее успешно конвертировать в Boolean(true).

Выход из создавшегося положения:
var key;
key = typeof(settings.value("key")) == "string" ? settings.value("key") == "true" : settings.value("key");

Postgres Notice Processing

В функции которую вы зарегеистрировали в качестве notice обработчика нельзя обращаться к соединению с базой данных. Например, нельзя в данной функции выполнить запрос использующий то же подключение, в котором и был сгенерирован notice.

03 мая 2010

Названия qt-сигналов

Не следует экспериментировать с перегрузкой сигналов/слотов, так как qt script bindings generator не разберется и не создаст нужных оболочек.

26 апреля 2010

Подписка на PostgreSQL записки.

Для того чтобы забирать нотисы генерируемые в процедурах postgresql, выполняем следующие шаги:



  • Подключаем заголовочные файлы: для qt sql драйвера и для pq библиотеки
    #include <QtSql/qsql_psql.h>
    #include "libpq-fe.h"
  • 24 апреля 2010

    Кроссплатформенный цветной вывод в консоль.

    Цветной вывод строки в *nix системах реализуеться с помощью вставки в строки специальных последовательностей. Данная последовательность должна начинаться с символа \033 (ESC).
    Для наглядного примера привожу картинку (взято здесь):


    Цветной вывод в win* системах реализуется вызовом функции SetConsoleTextAttribute.

    Задача: под *nix системой оставить все как есть, а в win среде написать парсер ESC-последовательности, и в зависимости от встречаемых параметров менять цвета вывода.

    17 апреля 2010

    CMake+Qt assistant

    In this post I write how install/register *.qch files of your project in assitant.

    16 апреля 2010

    15 апреля 2010

    Баг CMake 2.6-patch 4

    Заявленная переменная QT_TRANSLATIONS_DIR пуста после вызова find_package(Qt4 REQUIRED). Для исправления идем в исходники findQt4.cmake и копируем нахождение всяких директорий. Оно кстати делается с помощью вызова qmake -query.


    # additional qt functions
    # MINI HACK
    # find qt translations directory
    if (QT_LIBRARY_DIR AND NOT QT_TRANSLATIONS_DIR)
    exec_program(${QT_QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_TRANSLATIONS"
    OUTPUT_VARIABLE qt_translations_dir)
    file(TO_CMAKE_PATH "${qt_translations_dir}" qt_translations_dir)
    set(QT_TRANSLATIONS_DIR ${qt_translations_dir} CACHE PATH "The location of qt translations")
    endif (QT_LIBRARY_DIR AND NOT QT_TRANSLATIONS_DIR)