Attachment "snegopatwnd.js" to
ticket [05faeed476]
added by
kuntashov
2011-08-23 12:51:22.
$engine JScript
$uname snegopatwnd
$dname Показ окна Снегопата
var ActiveIniList
var wndStateProfilePath = "Snegopat/WndOpened"
// Скрипт для работы с окном Снегопата
// подключу глобальные контексты
addins.byUniqueName("global").object.connectGlobals(SelfScript)
// Класс для работы со списком аддинов
function AddinList(path)
{
this.path = path
this.textDoc = v8New("ТекстовыйДокумент")
var file = v8New("Файл", path)
if(file.Существует())
this.textDoc.Прочитать(path)
else
{
this.textDoc.УстановитьТекст("// Список загружаемых аддинов\r\nГруппа Проверка\r\n\tscript:scripts\\autosave.js\r\nКонецГруппы\r\n")
try{
this.textDoc.Записать(path)
}catch(e){}
if(!file.Существует())
throw "Не удалось записать файл " + path
}
this.lastModify = file.ПолучитьВремяИзменения()
this.parseFile();
}
AddinList.prototype.openIni = function()
{
this.textDoc.Показать(this.path, this.path)
}
// Объект описывающий группу в файле настройки
function addinListGroup(name, startLine, parent)
{
this.name = name
this.startLine = startLine
this.endLine = null
this.childs = new Array()
this.addins = new Array()
this.parent = parent
if(parent)
{
parent.childs.push(this)
this.level = parent.level + 1
}
else
this.level = 0
this.group = null
}
addinListGroup.prototype.findChild = function(name)
{
for(var i in this.childs)
{
if(this.childs[i].name == name)
return this.childs[i]
}
return null
}
// Объект описывающий addin в файле настройки
function addinListAddin(uri, active, lineNum, parent)
{
this.uri = uri
this.active = active
this.lineNum = lineNum
this.parent = parent
this.addins = null
parent.addins.push(this)
}
// Парсит файл загрузки аддинов и загружает их.
// Файл состоит из групп аддинов и строк загрузки аддинов.
// Группа аддинов обозначается как
// Группа Имя группы
// .... аддины и вложенные группы
// КонецГруппы
//
// Файл парсится построчно. Каждая строка СокрЛП'ится. Пустые строки пропускаются.
// Строки могут быть:
// Комментарий - начинается с "//". Пропускается.
// Начало группы - начинается с "Группа" (в любом регистре), за которой идут один или несколько пробельных символов, за которыми идет Имя группы
// Конец группы - "КонецГруппы" (в любом регистре)
// Временно отключенный аддин - начинается с "#".
// Все остальные строки считаются аддинами и пытаются загрузиться.
// В общем виде менеджер аддинов Снегопата использует отдельные загрузчики для разных видов аддинов.
// Какой загрузчик использовать, определяется по части строки загрузки до первого символа ":" (будем называть ее "протокол")
// По протоколу выбирается загрузчик, и строка загрузки передается уже ему.
// Как он ее интерпретирует - это уже его дело. Состав загрузчиков может быть расширен.
// Пока в снегопате реализован загрузка по протоколу "script:"
// Загрузчик скриптов рассматривает строку как указание пути к файлу скрипта.
// Путь может быть неполным, поиск осуществляется стандартно (WinAPI SearchFile), начиная от каталога, в котором лежит snegopat.dll
AddinList.prototype.parseFile = function()
{
this.root = new addinListGroup("Пользовательские аддины", 0, null)
var currentGroup = this.root
var lineCount = this.textDoc.КоличествоСтрок()
for(var lineNum = 1; lineNum <= lineCount; lineNum++)
{
var line = this.textDoc.ПолучитьСтроку(lineNum).replace(/^\s*|\s*$/g, '') // Это такой СокрЛП по JScript'овски
if(0 == line.length || '//' == line.substr(0, 2)) // Пропускаем пустые строки и комментарии
continue
// Проверим, не заголовок ли это группы
var isGroup = line.match(/^группа\s+(.+)$/i)
if(isGroup)
{
var nameOfGroup = isGroup[1]
var testGroup = currentGroup.findChild(nameOfGroup)
if(testGroup)
{
Message("Разбор списка аддинов. Файл " + this.path+ ", строка " + lineNum + ": группа " + nameOfGroup + " уже есть", mExc1)
currentGroup = testGroup
}
else
currentGroup = new addinListGroup(nameOfGroup, lineNum, currentGroup)
}
// Проверим, не конец ли это группы
else if(isGroup = line.match(/^конецгруппы$/i))
{
if(!currentGroup.parent)
Message("Разбор списка аддинов. Файл " + this.path + ", строка " + lineNum + ": Лишний КонецГруппы", mExc1)
else
{
currentGroup.endLine = lineNum
currentGroup = currentGroup.parent
}
}
// Значит, это строка загрузки аддина
else
{
var active = true
if('#' == line.charAt(0))
{
active = false
line = line.substr(1)
}
new addinListAddin(line, active, lineNum, currentGroup)
}
}
var stackDepth = 0
while(currentGroup.parent)
{
stackDepth++
this.textDoc.ДобавитьСтроку("КонецГруппы")
currentGroup.endLine = lineNum
lineNum++
currentGroup = currentGroup.parent
}
if(stackDepth)
Message("Разбор списка аддинов. Файл " + this.path+ ": Не хватает КонецГруппы, " + stackDepth + " шт.", mInfo)
}
function AboutDlg()
{
this.form = loadScriptForm("core\\std\\forms\\about.ssf", this)
this.form.ЭлементыФормы.Версия.Заголовок = "Текущая версия: " + sVersion
this.form.ОткрытьМодально()
}
AboutDlg.prototype.СсылкаНажатие = function(Элемент)
{
ЗапуститьПриложение("http://snegopat.ru")
}
AboutDlg.prototype.ОКНажатие = function(Элемент)
{
this.form.Закрыть()
}
function SnegopatWnd()
{
SnegopatWnd.one = this
this.form = loadScriptForm("core\\std\\forms\\snegopat.ssf", this)
// Получим ссылку на коллекцию кнопок контекстного меню
// Добавим колонку для хранения ссылки на группу/аддин
this.form.AddinsTree.Колонки.Добавить("object")
with(this.form)
{
КлючУникальности = "SnegopatMainForm"
КлючСохраненияПоложенияОкна = "SnegopatMainForm"
this.refreshAddinTree()
}
this.menu = this.form.ЭлементыФормы.CmdBar.Кнопки.Найти("Действия").Кнопки
this.btnForGroup = new Array()
this.btnForAddin = new Array()
this.btnForGroup.push(this.menu.Найти("ДобавитьГруппу"))
var loadIdx = this.menu.Индекс(this.btnForGroup[0]) + 1
var loadersString = new VBArray(addins.getLoaderCommands()).toArray()
for(var k in loadersString)
{
var cmd = loadersString[k].split('|')
this.btnForGroup.push(this.menu.Вставить(loadIdx, cmd[1], v8New("ПеречислениеТипКнопкиКоманднойПанели").Действие, cmd[0] + " ...", v8New("Действие", "ХочуЗагрузить")))
loadIdx++
}
this.btnForAddin.push(this.menu.Найти("UnloadScript"))
this.btnForAddin.push(this.menu.Найти("RestartCurrentScript"))
this.scriptsMenuItems = v8New("Структура");
// Восстановим состояние окна
profileRoot.createValue(wndStateProfilePath, true, pflSnegopat)
var isWndOpened = profileRoot.getValue(wndStateProfilePath)
if(isWndOpened)
this.form.Открыть()
}
SnegopatWnd.prototype.ХочуЗагрузить = function(Кнопка)
{
this.loadedGroup = this.form.ЭлементыФормы.AddinsTree.ТекущаяСтрока.object
try{
addins.selectAndLoad(Кнопка.val.Имя, this.loadedGroup)
}catch(e)
{
Message("Ошибка при загрузке: " + e.description)
}
delete this.loadedGroup
}
SnegopatWnd.prototype.refreshAddinTree = function()
{
var rows = this.form.AddinsTree.Строки
rows.Очистить()
this.fillAddinTree(rows, addins.root)
}
SnegopatWnd.prototype.fillAddinTree = function(rows, group)
{
for(var child = group.child; child; child = child.next)
{
var row = rows.Добавить()
row.Picture = 0
row.Addin = child.name
row.object = child
this.fillAddinTree(row.Строки, child)
}
for(var i = 0, count = group.addinsCount; i < count; i++)
{
var row = rows.Добавить()
var addin = group.addin(i)
row.Picture = 2
row.Addin = addin.displayName
row.uniqueName = addin.uniqueName
row.fullPath = addin.fullPath
row.object = addin
}
}
SnegopatWnd.prototype.AddinsTreeПриВыводеСтроки = function(Элемент, ОформлениеСтроки, ДанныеСтроки)
{
var isAddin = ДанныеСтроки.val.Picture != 0
}
SnegopatWnd.prototype.AddinsTreeПриАктивизацииСтроки = function(Элемент)
{
var current = Элемент.val.ТекущаяСтрока
var isAddin = current.Picture != 0
var isInUserGroup = false
if(ActiveIniList)
{
var testGroup = isAddin ? current.Родитель : current
while(testGroup)
{
if(testGroup.object == ActiveIniList.root.group)
{
isInUserGroup = true
break
}
testGroup = testGroup.Родитель
}
}
for(var k in this.btnForGroup) // Команды для работы с группами доступны если стоим на пользовательской группе
this.btnForGroup[k].Доступность = !isAddin && isInUserGroup
for(var k in this.btnForAddin)
{
this.btnForAddin[k].Доступность = isAddin && isInUserGroup
if(isAddin)
this.btnForAddin[k].Текст = this.btnForAddin[k].Текст.replace(/\s+.*|$/, ' ' + current.object.displayName)
else
this.btnForAddin[k].Текст = this.btnForAddin[k].Текст.replace(/\s+.*$/, '')
}
}
SnegopatWnd.prototype.ПриОткрытии = function()
{
//Message("Открыли окно снегопата")
}
SnegopatWnd.prototype.ПриЗакрытии = function()
{
//Message("Закрыли окно снегопата")
}
SnegopatWnd.prototype.CmdBaractSnegopatSettings = function(Кнопка)
{
addins.byUniqueName("settings").invokeMacros("ОткрытьНастройкиСнегопата")
}
SnegopatWnd.prototype.SetupKeyboard = function(Кнопка)
{
addins.byUniqueName("hotkeys").invokeMacros("РедактироватьГорячиеКлавиши")
}
SnegopatWnd.prototype.CmdBarВыполнитьМакрос = function(Кнопка)
{
addins.byUniqueName("SnegopatMainScript").invokeMacros("ВыбратьИВыполнитьМакрос")
}
SnegopatWnd.prototype.CmdBarДобавитьГруппу = function(Кнопка)
{
/*
// В JScript'е это не работает, тк не поддерживается передача параметров по ссылке :(
var text = ''
globalContext("{38406666-F954-489E-BB5B-B0E6C0C81AFB}").ВвестиСтроку(text, "Укажите название группы")
Message(text)
*/
// Приходится извращаться через VB
var vbs = addins.byUniqueName("vbs").object
//var input = vbs.DoEval('InputBox("Укажите название группы", "Снегопат")') // Это некошерно, некрасивое окно появляется
vbs.result = ""
input = vbs.DoExecute('InputString result, "Укажите название группы"')
if(!input.length)
return
var currentRow = this.form.ЭлементыФормы.AddinsTree.ТекущаяСтрока
// Проверим, что нет такой группы
for(var child = currentRow.object.child ; child; child = child.next)
{
if(child.name == input)
{
MessageBox("Группа с именем " + input + " уже существует")
return
}
}
var group = currentRow.object.addGroup(input)
if(group)
{
var row = currentRow.Строки.Добавить()
row.Picture = 0
row.Addin = group.name
row.object = group
this.form.ЭлементыФормы.AddinsTree.ТекущаяСтрока = row
}
}
SnegopatWnd.prototype.CmdBarEditScriptForm = function(Кнопка)
{
addins.byUniqueName("SnegopatMainScript").invokeMacros("ОткрытьФормуСкрипта")
}
SnegopatWnd.prototype.CmdBarNewScriptForm = function(Кнопка)
{
addins.byUniqueName("SnegopatMainScript").invokeMacros("НоваяФормаСкрипта")
}
SnegopatWnd.prototype.CmdBarОткрытьИни = function(Кнопка)
{
ActiveIniList.openIni()
}
SnegopatWnd.prototype.onLoadAddin = function(addin)
{
if(this.loadedGroup) // Это загрузился аддин по нашей команде "Загрузить"
{
var row = this.form.ЭлементыФормы.AddinsTree.ТекущаяСтрока.Строки.Добавить()
row.Picture = 2
row.Addin = addin.displayName
row.uniqueName = addin.uniqueName
row.fullPath = addin.fullPath
row.object = addin
this.form.ЭлементыФормы.AddinsTree.ТекущаяСтрока = row
}
else if(this.reloadAddinRow) // Это загрузился аддин по команде "Перезагрузить"
{
this.reloadAddinRow.Addin = addin.displayName
this.reloadAddinRow.uniqueName = addin.uniqueName
this.reloadAddinRow.fullPath = addin.fullPath
this.reloadAddinRow.object = addin
}
else // Аддин типа где-то со стороны загрузился
this.refreshAddinTree()
}
SnegopatWnd.prototype.onUnLoadAddin = function(addin)
{
if(this.unloadedAddin) // Это выгружается аддин по команде "Выгрузить аддин"
return
this.refreshAddinTree()
}
// Выгрузить текущий аддин
SnegopatWnd.prototype.CmdBarUnloadScript = function(Кнопка)
{
var currentRow = this.form.ЭлементыФормы.AddinsTree.ТекущаяСтрока
this.unloadedAddin = currentRow.object
var displayName = this.unloadedAddin.displayName
try{
addins.unloadAddin(this.unloadedAddin);
}
catch(e)
{
Message("Ошибка при выгрузке аддина " + displayName + ": " + e.description)
}
if(!this.unloadedAddin.uniqueName.length) // аддин реально выгрузился
currentRow.Родитель.Строки.Удалить(currentRow)
delete this.unloadedAddin
}
SnegopatWnd.prototype.CmdBarRestartCurrentScript = function(Кнопка)
{
// Сначала надо выгрузить аддин
var currentRow = this.form.ЭлементыФормы.AddinsTree.ТекущаяСтрока
this.unloadedAddin = currentRow.object
var displayName = this.unloadedAddin.displayName
var loadString = this.unloadedAddin.fullPath
var addinGroup = this.unloadedAddin.group
try{
addins.unloadAddin(this.unloadedAddin);
}
catch(e)
{
Message("Ошибка при выгрузке аддина " + displayName + ": " + e.description)
}
if(!this.unloadedAddin.uniqueName.length) // аддин реально выгрузился
{
this.reloadAddinRow = currentRow
try{
addins.loadAddin(loadString, addinGroup)
}catch(e)
{
Message("Ошибка при загрузке: " + e.description)
}
delete this.reloadAddinRow
}
delete this.unloadedAddin
}
SnegopatWnd.prototype.CmdBarAbout = function(Кнопка)
{
new AboutDlg()
}
function Designer::beforeExitApp()
{
var isWndOpened = SnegopatWnd.one && SnegopatWnd.one.form.Открыта()
profileRoot.setValue(wndStateProfilePath, isWndOpened)
}
function Designer::onLoadAddin(addin)
{
if(SnegopatWnd.one)
SnegopatWnd.one.onLoadAddin(addin)
}
function Designer::onUnLoadAddin(addin)
{
if(SnegopatWnd.one)
SnegopatWnd.one.onUnLoadAddin(addin)
}
function getAddinList(path)
{
ActiveIniList = new AddinList(path)
return ActiveIniList
}
function getSnegopatWnd()
{
if(!SnegopatWnd.one)
new SnegopatWnd()
return SnegopatWnd.one
}
// Возвращает следующий по порядку идентификатор элемента контекстного меню.
SnegopatWnd.prototype.GetNextContextMenuId = function()
{
if (!this.contextMenuHandler)
{
return 'cmdExtMenuItem1';
}
return 'cmdExtMenuItem' + this.contextMenuHandlers.Количество();
}
// Обработчик выбора добавленного пункта контекстного меню.
SnegopatWnd.prototype.OnExtMenuItemClick = function(Кнопка)
{
var handler = this.contextMenuHandlers.Получить(Кнопка.val.Имя);
if (handler)
{
handler(this.form.ЭлементыФормы.AddinsTree.ТекущаяСтрока);
}
}
// Добавить пункт в контекстное меню окна Снегопата.
// Пример использования в стороннем скрипте:
//
// var snegopatWnd = addins.byUniqueName("snegopatwnd").object.getSnegopatWnd();
// snegopatWnd.AddContextMenuItem("Выполнить что-то", function(ТекущаяСтрока) { Message("Вызван обработчик"); } );
SnegopatWnd.prototype.AddContextMenuItem = function(title, handler)
{
var insertSplitter = false;
if (!this.contextMenuHandlers)
{
this.contextMenuHandlers = v8New("Соответствие");
insertSplitter = true;
}
if (insertSplitter)
{
this.menu.Добавить("cmdExtMenuSplitter", v8New("ПеречислениеТипКнопкиКоманднойПанели").Разделитель);
}
var newItemId = this.GetNextContextMenuId();
this.contextMenuHandlers.Вставить(newItemId, handler);
this.menu.Добавить(newItemId, v8New("ПеречислениеТипКнопкиКоманднойПанели").Действие, title, v8New("Действие", "OnExtMenuItemClick"));
}