среда, 27 января 2010 г.

Продолжаем удалять файлы и каталоги

Функция рекурсивного удаления папок не работает если в папке есть файлы только для чтения.
Функция QFile::remove() при попытке удалить такой файл возвращает false. Чтобы этого избежать нужно выставлять права для таких файлов. В Qt для этого есть функция
bool QFile::setPermissions ( const QString & fileNamePermissions 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.

Вот пример сгенеренного им кода.

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.

На мой взгляд - лучшее решение для вставки кода в блог.

понедельник, 7 декабря 2009 г.

Настоящий программист

Понравилась цитата:
Настоящий программист не использует буфер обмена. (с)

От себя добавлю - Настоящий программист использует наследование.

четверг, 26 ноября 2009 г.

Недалекий gcc

Сегодня случилось компилировать кусок с рекурсивным удалением каталогов под Linux.
Здесь про рекурсивное удаление
Компилятор gcc преподнес сюрприз. Не хотел компилировать безобидный кусок кода:
int removeFolder(QDir & dir)
{
......
QString entryAbsPath = dir.absolutePath() + "/" + entry;
removeFolder(QDir(entryAbsPath));
......
}

То есть здесь идет рекурсивный вызов функции removeFolder(QDir &). В качестве параметра я передаю временный объект QDir, предполагая, что компилятор сможет получить ссылку на временный объект. Это не вызывает трудностей у MS Studio 2005, но повергает в шок gcc.
Пришлось за него самому создавать объект. В итоге код пришлось переписать в :
int removeFolder(QDir & dir)
{
......
QString entryAbsPath = dir.absolutePath() + "/" + entry;
QDir dr(entryAbsPath);
removeFolder(dr);
......
}

пятница, 30 октября 2009 г.

Рекурсивное удаление каталогов в Qt

Удаляем рекурсивно папки.

//Функция удаления папки
int removeFolder(QDir & dir)
{


int
res = 0;
//Получаем список каталогов
QStringList lstDirs = dir.entryList(QDir::Dirs |

QDir::AllDirs |
QDir::NoDotAndDotDot);
//Получаем список файлов
QStringList lstFiles = dir.entryList(QDir::Files);

//Удаляем файлы
foreach (QString entry, lstFiles)
{

QString entryAbsPath = dir.absolutePath() + "/" + entry;

QFile::remove(entryAbsPath);
}


//Для папок делаем рекурсивный вызов
foreach (QString entry, lstDirs)
{


QString entryAbsPath = dir.absolutePath() + "/" + entry;

removeFolder(QDir(entryAbsPath));
}


//Удаляем обрабатываемую папку
if (!QDir().rmdir(dir.absolutePath()))
{


res = 1;
}

return
res;
}

четверг, 29 октября 2009 г.

Расширение типов зависимостей в форме ввода

Некоторые люди спрашивают, почему у тебя в форме ввода зависимости между компонентами обусловлены по RTTI? Ведь это налагает ограничения на разновидности зависимостей. То есть, ты четко прописываешь связку, например, FSexEdit (выбор пола) и FComboList (список фамилий) и в зависимости от пола меняешь окончания фамилий. А если тебе надо будет добавить некую другую зависимость, когда в FComboList будут не фамилии а нечто другое, как тогда?

Отвечаю, добавление новой зависимости не составит труда. В утилите Rule нужно добавить третий параметр - тип зависимости.

Вот код утилиты Rule::applyRule

void Rule::applyRule(const AbstractFormComponent & master, AbstractFormComponent & slave)
{

   //преобразование мастера   const FSexEdit * masterSex = dynamic_cast<const FSexEdit *>(&master);

   //преобразование раба   FComboTextList * slaveCombo = dynamic_cast<FComboTextList *>(&slave);

   //зависимости от секса   if (masterSex)
   {
      if (slaveCombo)
      {

         apply(*masterSex, *slaveCombo);
      }
   }
}

Как видно из кода - я делаю динамическое преобразование с помощью dynamic_cast, а затем в зависимости от результата вызываю функцию apply, аргументами которой являются уже конкретные типы FSexEdit и FComboTextList.
Чтобы расширить набор зависимостей, мне нужно в функции apply добавить третий параметр - вид зависимости.
void Rule::apply(const FSexEdit & sex, FComboTextList & combo, int depType)


Тип зависимости будет узнавать функция applyRule из экземпляра master.

Так, что изменения минимальны, код легко расширяется. Все изменения не выходят за границы утилиты класса.

вторник, 27 октября 2009 г.

Реализация зависимостей в форме ввода

Сегодня набросал механизм зависимостей. Вроде работает, но внутреннее чувство неправильности сделанного осталось.
Мне не нравится, что я использовал:
- множественное наследование
- RTTI

Это ведет к усложнению проекта. Проект должен быть прост и красив, но сделать просто очень трудно.

Дальше технические детали.

понедельник, 26 октября 2009 г.

Ваяем форму ввода

Продолжаю ваять Форму ввода текста.

Пока остановился на том, что все компоненты, родные Qt и самописные должны наследовать от некого абстрактного класса, который я назвал AbstractFormComponent.

Класс содержит ряд чисто виртуальных функций, которые, следовательно, нужно переобпределять потомкам.
Интерфейс класса пока выглядит так.


class AbstractFormComponent
{
public:
void setName(const QString & name)
{
name_ = name;
}

QString name() const
{
return name_;
}
virtual void setValue(const QVariant &) = 0;
virtual QVariant value() const = 0;

protected:
virtual QWidget * widget() const = 0;
virtual void setCaps(Caps) = 0;

private:
QString name_;

};


Класс содержит пару функций для задания имени компонента, чтобы каждый компонент мог сказать как его зовут.
Дальше идут две основополагающие функции setValue и value. Они устанавливают и получают значение компонента.
Здесь пришлось использовать тип QVariant, хотя мне хотелось бы это сделать на чистом С. Тип QVariant удобен тем, что может хранить любой тип - int, QString, QDate и многие другие.
Каждый компонент сам понимает с каким типом он работает, преобразует QVariant в нужный тип и работает с ним.

Далее идет функция widget() - она возвращает виджет, который будет отражен на форме.

Такой подход, т.е. наследование всех компоненто от единой основы, позволяет отделить интерфейс компонента от реализации. Например, если захочу я переписать компонент QComboBox, то все что мне понадобится, чтобы пристыковать новый компонент - это соблюсти небольшой интерфейс абстрактного класса AbstractFormComponent.

А все компоненты я могу поместить в вектор

QVector<AbstractFormComponent *> components_;

и работать с ними как с одним типом.

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