пʼятницю, 29 жовтня 2010 р.

Встановлення ваги для модуля Drupal (Setting weight for the module)

Встановити вагу (приоритет) для модуля можна встановити додаванням наступного рядка в "hook_install" хук:

db_query("UPDATE {system} SET weight = 100000 WHERE name = 'ics_module'");


Хуки даного модуля виконуватимуться після хуків модулів з меншими вагами.

пʼятницю, 22 жовтня 2010 р.

ID змінених рядків в PostgreSQL

Нещодавно виникло питання як узнати ID останнього вставленого рядка в таблиці для PostgreSQL. В Perl'і це робиться через dbh->last_insert_id.

Виявилося, що можливо узнати це і безпосередньо через SQL запит, слід лише використати службове слово RETURNING.

Для таблиці, створеної наступною командою:
CREATE TABLE test_table
(
  id serial NOT NULL,
  "name" character varying NOT NULL,
  PRIMARY KEY (id)
);


Операція INSERT з поверненням ID виглядатиме так:
INSERT INTO test_table (name)
    VALUES ('test name')
    RETURNING id; 

Якщо у нас є більше одного рядка з name = 'test name', наступна операція UPDATE поверне список змінених ID:
UPDATE test_table
SET
  name = 'TEST name'
WHERE
  name = 'test name'
RETURNING id;

вівторок, 18 травня 2010 р.

Як зробити блок, що розгортається в QT (fold/unfold block)

Задача: зробити частину вікна діалога такою, що згортається і розгортається по кнопці, схоже до folding в Drupal чи Vim.
Згорнутий блок:


Розгорнутий блок:

Після довгих пошуків я знайшов такий шлях вирішення проблеми:
  1. Всі віджети діалогу мають бути поміщені в QLayout зі встановленим "SetDefaultConstraint" (в даній, 4.6 версії QT - по замовчуванню).
  2. Всі дочірні віджети першого рівня кожного QLayout повинні мати "Vertical Policy" встановлені в "Fixed", інакше вони будуть розтягуватися при зміні конфігурації вікна.
  3. Створити кнопку типу QToolButton, якщо ми хочемо мати кнопку з гарненьким трикутничком, який повертається, як на скріншоті. Я її назвав "advSettingsButton". Трикутник: в дизайнері QT Creator'а встановити властивість arrowType рівною RightArrow.
  4. Для кнопки "advSettingsButton", яка згортає/розгортає блок, слід написати подібний код:
    void OurProxyDialog::on_advSettingsButton_clicked()
    {
        // If advanced settings are hidden, show
        if (m_ui->capabilitiesBox->isHidden()) {
            m_ui->advSettingsButton->setArrowType(Qt::DownArrow);
            m_ui->capabilitiesBox->show();
        } else if (m_ui->capabilitiesBox->isVisible()) {
            // If advanced settings are shown, hide
            m_ui->advSettingsButton->setArrowType(Qt::RightArrow);
            m_ui->capabilitiesBox->hide();
        }
        adjustSize();
    }
    

    Тут "capabilitiesBox" це якраз нижній блок (QGroupBox), який згортається/розгортається.
  5. Для краси в цієї кнопки прибрані границі через встановлення "styleSheet" властивості рівною "border: 0;". Також можна додати градієнт там же.
  6. Для конструктора діалогу встановити таку обробку, щоб блок був схований при створенні вікна:
    OurProxyDialog::OurProxyDialog(QWidget *parent) :
        QDialog(parent),
        m_ui(new Ui::OurProxyDialog)
    {
        m_ui->setupUi(this);
    
        // Hide advanced settings
        m_ui->capabilitiesBox->hide();
        setMaximumHeight(0);
        adjustSize();
    }
    

Ніби все.

    PS. Кінцевий варіант коду мені допомогло написати ось це джерело (щодо зміни розміру вікна після видалення певного віджету): http://lists.trolltech.com/qt-interest/2006-10/thread00212-0.html

    четвер, 13 травня 2010 р.

    Універсальний тип даних для вказівника (C/C++ pointer)

    Вирішував нещодавно цікаву задачу: як правильно здійснити приведення типу для вказівника типу (void *)? Якщо на 32-бітних системах розмір вказівника рівний розміру типу даних int, то в 64-бітних системах усе залежить від реалізації. Наприклад, тип int може бути як 32-бітним (Microsoft Win64, більшість UNIX-подібних систем), так і 64-бітним (якщо система використовує модель даних ILP64 або SILP64). Аналогічна ситуація і з типом long: він 64-бітний на більшості систем, проте є системи, де його розмірність рівна 32 біт. Детальніше про це можна прочитати тут:
    http://en.wikipedia.org/wiki/64-bit#Specific_C-language_data_models.

    Отже, задача звелася до того, що слід мати універсальний тип даних, розмірність якого завжди відповідає розмірності вказівника. Як виявилося, в UNIX-подібних системах існують спеціальні типи даних, спроектовані для операцій з вказівниками, такі як ptrdiff_t, intptr_t, uintptr_t.
    Тип ptrdiff_t призначений зберігання результатів віднімання вказівників і є знаковим.
    Тип intptr_t є його синонімом.
    Тип uintptr_t є беззнаковим цілочисельним типом і здатен безпечно зберігати у собі вказівник незалежно від розрядності платформи.

    Отже, для моєї задачі потрібен був тип uintptr_t. Слід було лише виявити, для якої платформи який заголовний файл (header) слід включити, щоб використати цей тип.
    Ось список заголовних файлів відповідно для системи:
    GNU/Linux - stdint.h;
    Solaris - inttypes.h;
    AIX - inttypes.h;
    IRIX - додадковий заголовний файл не потрібен;
    HP-UX - sys/wsio.h.

    Відповідно, універсальний код для включення типу uintptr_t:

    #if defined(__hpux)
    #include <sys/wsio.h>
    #else
    # if defined(__sun) || defined(_AIX)
    #include <inttypes.h>
    # else
    # ifndef __sgi
    #include <stdint.h>
    # endif
    # endif
    #endif

    середу, 14 квітня 2010 р.

    Проблеми з повторними генераціями сигналу finished для QNetworkReply

    Вчора зіткнувся з досить неочевидною проблемою при тестуванні QT-аплікації. Після відсилання мережевого запиту обробка відповіді відбувається у функції, прив'язаній до сигналу finished.
    Робота з мережевими запитами в QT описана ось тут Creating_an_HTTP_network_request_in_Qt

    Ось, власне, прив'язка у моєму випадку:
    connect(_networkManager, SIGNAL(finished(QNetworkReply*)), this,
        SLOT(replyFinished(QNetworkReply*)));
    

    Виявилося, що цей сигнал генерується декілька разів: QNetworkReply завершив роботу, перед знищенням об'єкта QNetworkReply або під час його закриття функціями close() чи abort(). При цьому лише у першому випадку з нього можна щось прочитати, у решті - ні, що призводить до помилок при парсінгу даних і зупинки обробки наступних запитів (у моєму випадку відбувається перевірка статусу попереднього запиту перед відправкою наступного).

    Правильним рішенням було відключити всі слоти від сигналів QNetworkReply, щоб не отримувати їх після завершення обробки даних. Ось як це реалізовано:
    void MyClass::replyFinished(QNetworkReply* reply) {
        // --------------------------------------
        // Тут насправді міститься обробка даних
        // --------------------------------------
    
        // Close and clean up.
        m_networkManager->disconnect();
        reply->close();
        reply->deleteLater();
    }