вторник, 5 августа 2014 г.

Сезон заметок о веб-разработке.
Очень полезное и тяжело находимое: способ вывести на печать только один блок с веб-страницы.
В моем случае просили вывести на печать по кнопке карту.
Базовый источник информации: http://blog.ircit.ru/post/javascript-pechat-otdelnogo-bloka-stranitsy/  В нем содержится подробное объяснение и несколько полезных дополнений.

В сухом остатке для себя.
1. Кнопка "Распечатать"
<a id="printBlock" href="#">Распечатать</a>

2. Стили для @media print
<style>  
@media print
{
   .printSelected>* {display: none; }      
   .printSelected>.printSelection { display: block !important; }
}  

.printSelection{display:none;}
</style>

3. Скрипт:
<script type="text/javascript">
$(function() {
  
    $('#printBlock').click(function(){      

 $('body').addClass('printSelected'); //добавляем класс <body>     

$('body').append("<div class='printSelection'></div>"); //создаем "призрачный" блок для печати

$('.item-page img').clone().appendTo('.printSelection');  // вставляем в блок то, что нужно вывести на печать (в данном случае лишь картинку)   .item-page - класс родительского блока моей картинки

$("<p><img src='/images/print-logo.png'></p>").insertBefore('.printSelection img'); // в шаблон печати добавляем сверху логотип компании   
window.print(); // выводи на печать   
});
  });
</script>

4. Собственно все. При нажатии на ссылку должен открываться диалог печати страницы с ее предпросмотром.


четверг, 19 июня 2014 г.

Давно стоило об этом написать, но все как-то руки не доходили.
Чуть ниже я описывала способ как сократить ручную работу при наследовании прав пользователей на таблицы в Informix.
Пост необходимо отредактировать из-за нюанса, который я сейчас опишу.
В системных таблицах Informix есть таблицы пользователей (sysusers), таблица таблиц (systables) и таблица соответствия прав пользователей и таблиц (systabauth). Но есть нюанс. В таблице systabauth есть ссылка на systables. Но нету ссылки на sysusers. Пользователь записывается в строчном виде из нструкции "GRANT" и потом по строковому соответствию ищется при "REMOVE".
Отсюда мы сталкиваемся со всеми проблемами присущими строковому представлению. А именно:
USER_NAME <> "USER_NAME" <> " USER_NAME " <> " USER_NAME" <> "user_name"

В том виде, в котором я делала запрос:
SELECT 'GRANT DELETE ON table_name2 TO' ,grantee, ';' FROM systabauth WHERE ...
Я получала запрос вида: GRANT DELETE ON table_name2 TO USER_NAME FROM ...

Запрос выполняется корректно. Однако в таблицу systabauth записывался пользователь с именем в нижнем регистре (которого по сути не существует). А это, как мы уже знаем - совершенно другой пользователь. Как следствие - права вроде как есть. Но их на самом деле нет.

Недолго думая я вставила кавычки и получила запрос:
SELECT 'GRANT DELETE ON table_name2 TO "' ,grantee, '";' FROM systabauth WHERE ...
А после копирования результата в строку запроса
GRANT DELETE ON table_name2 TO " USER_NAME " FROM ...

На самом деле пробелы - это тоже некорректно, но с ними просто бороться путем автозамены, увы, пока другого способа я не нашла. Но после ликвидации пробелов все работает правильно.

Далее в выпуске - системные таблицы mysql.

вторник, 1 апреля 2014 г.

Самое сложное, когда переходишь с Windows Forms на WPF - это слегка изменить свое отношение к элементам интерфейса.

В первую очередь - это верстка. Матерые опытные люди встают в тупик, когда им предлагается не просто раскидать кнопочки по форме, а создать структуру. Не побоюсь этого слова макет. Надо забыть про абсолютные размеры и, тем более, абсолютное позиционирование элементов друг относительно друга.

Второе - способ сделать разные красивые штуки. Утопленные групбоксы с тенью, шаблоны красивых кнопочек. Работа по созданию своей библиотеки часто-используемых элементов - в данном случае становится рутинной. Или должна таковой становиться. В качестве примера: TimePicker - потому что в стандартных библиотеках нет такого элемента, только дата. А нам нужен все время.

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

Когда говорят "А давайте внедрять WPF вместо Windows Forms?" самый первый возникающий вопрос: "А что нам это даст?". И инициатор такой радостный: "Красивки!!!".
Тем не менее, прежде чем в проекте появится что-то более зрелое, чем радужный градиент на фоне формы новичку, привыкшему что элементы никак или почти никак друг с другом не связаны, придется сломать себе мозг.
Фокус, оказывается в том, что не надо долго и сложно пытать свойства каждого отдельного элемента. Не надо рисовать в фотошопе, чтобы подгрузить в качестве фона. Надо попытаться увидеть или придумать как решать задачу с точки зрения глубины макета.


среда, 26 марта 2014 г.

Дано: IBM Informix, Четыре похожих, но разных базы, кучу пользователей (частично совпадающих, частично нет), кучу прав этих пользователей на различные куски этих баз. Server Studio и в ряде случаев только dbaccess.
Задача 1: Каждый раз создавая в подсхеме базы таблицу, с внешними ключами и каскадным удалением необходимо проверить права на удаление из верхних таблиц и дать им права на удаление из новой таблицы. Чтобы каскад не рушился.
Задача 2: Когда возникает необходимость создать нового пользователя, ему иногда надо скопировать права другого пользователя.
Задача 3: Поддержание в актуальном состоянии отчетов и сводок о правах пользователей.
А также: Прочие задачи формирования или получения списка прав.

Решение:
1. Получить из системной таблицы systables идентификатор исходной таблицы SELECT tabid FROM systables WHERE tabname="table_name1".
2. Для этого идентициатора таблицы из таблицы systabauth выбрать права.
3. Добавить в запрос несколько формальных столбцов, как упоминалось ранее.
4. На выходе получить таблицу, содержание которой может быть скопировано в качестве запроса.

Итого в качестве примера .
Запрос на дублирование прав из таблицы table_name1 в таблицу table_name2.

SELECT 'GRANT', CASE tabauth
WHEN "s--------" THEN "SELECT"
WHEN "su-id----" THEN "SELECT, UPDATE, INSERT, DELETE"
WHEN "su-i-----" THEN "SELECT, UPDATE, INSERT"
WHEN "su-------" THEN "SELECT, UPDATE"
WHEN "s--i-----" THEN "SELECT, INSERT"
WHEN "----d----" THEN "DELETE"
WHEN "---id----" THEN "INSERT, DELETE"
ELSE tabauth END CASE, 'ON table_name2 TO' ,grantee, ';' FROM systabauth WHERE tabid IN (SELECT tabid FROM systables WHERE tabname="table_name1");

Запрос на получение права DELETE на таблицу table_name2, для всех у кого есть DELETE на таблицу table_name1.

SELECT 'GRANT DELETE ON table_name2 TO ',grantee, ';' FROM systabauth WHERE (tabauth="----d----" OR tabauth="su-id----" OR tabauth="---id----")
AND tabid IN (SELECT tabid FROM systables WHERE tabname="table_name1");

UPD
В запросе допущена ошибка (не мешающая, впрочем, выполнению запроса, но). Ошибка и ее истоки описаны позднее http://karhet.blogspot.ru/2014/06/blog-post.html. 

понедельник, 17 марта 2014 г.

Последнее время, я часто встречаю еще более начинающих программистов, чем я.
(Новый набор в отделе, ага).

Всем им хочется сказать только одно: "Учитесь гуглить, бандерлоги."  Потому что это невозможно.

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

среда, 26 февраля 2014 г.

Делфи - очень делфи.

Допустим у вас есть ADQuery, в которую вы пишете запрос. Допустим UPDATE.
Допустим вам надо дать пользователю возможность отредактировать любое сочетание полей в строке таблицы. И, например, чтобы это сделать, вам надо удалить записанное ранее значение во внешнем ключе. т.е. записать туда NULL. Не 0 - а именно, что ничего.

Вы пишете запрос, добавляете туда параметр... Ну, например:

SQL.Clear;
Params.Clear;
SQL.Add('UPDATE my_table SET my_fk = :NullParam;');


...И начинаете думать, как же мне засунуть туда NULL?
Пара минут гуглинга и вы счастливо пишете что-то в духе:

ParamByName('NullParam').Clear;
ExecSQL;


И... Получаете ошибку "... [AnyDAC][Phys][ODBC]-335.Parameter [NULLPARAM] data typ is unknown. ..."

Как это неизвестный тип, думаете вы?..  Какой ему нужен тип?.. Может быть это что-то вроде " int? " в Шарпе?.. Но нет, просто где-то внутри ему нужен тип параметра, чтобы собрать запрос. И он нужен до значения.
Итак. Нужен тип параметра, чтобы все это собрать. А как задать тип параметра? Что мы делаем обычно. Обычно, мы "отипиваем" параметр и даем ему значение:

ParamByName('NullParam').AsInteger = some_int_var;

Однако, выражение AsInteger требует правой части, написать просто:

ParamByName('NullParam').AsInteger;
ParamByName('NullParam').Clear;


...нам ничем не поможет. Зато нас вполне устроит

ParamByName('NullParam').AsInteger = 0;
ParamByName('NullParam').Clear;


Ура! Все работает.
Однако, любопытно, какой именно вы дадите параметру тип, уже никого после этого не волнует. Запрос будет выполнен в любом случае (если только он не противоречит структуре базы).

Такое вот Делфи.

понедельник, 24 февраля 2014 г.

Honestly, english text is not my strong side. I am too lazy to translate my thoughts. In fact, I sometimes realize I am too lazy to form my thought. So, it is expediant to go on in russian.

Вчера я узнала, что при разработке приложения на андроид все тексты в визуальном оформлении являются переменными .xml. Звучит жутко, а что делать, если читать мануалы сначала и внимательно мне было лень.

Откровенно говоря, это первый раз в моей практике, когда мне удалось разобраться как ставить и настраивать среду разработки до того, как мне удалось понять, что с этой средой делать дальше.

Вывод: быстро-находимые статьи на хабре по теме "как начать разработку под андроид?" пригодны (ну может со второй попытки), чтобы разобраться в вопросе среды разработки. А вот чтобы разобраться с принципами, все-таки придется почитать длинные и нудные мануалы.