omq/ui_main_form.go

394 lines
12 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"fmt"
"os"
"path/filepath"
"slices"
"strings"
"time"
"github.com/BurntSushi/toml"
"github.com/ying32/govcl/vcl"
"github.com/ying32/govcl/vcl/types"
)
type TMainForm struct {
*vcl.TForm
MainMenu *vcl.TMainMenu
ChangePasswordMenuItem *vcl.TMenuItem
AboutMenuItem *vcl.TMenuItem
PageControl *vcl.TPageControl
TabSheet1 *vcl.TTabSheet
GroupBox *vcl.TGroupBox
ConfigLabel *vcl.TLabel
ConfigComboBox *vcl.TComboBox
SqlFileLabel *vcl.TLabel
SqlFileComboBox *vcl.TComboBox
ExportFormatLabel *vcl.TLabel
ExportFormatComboBox *vcl.TComboBox
CharsetLabel *vcl.TLabel
CharsetComboBox *vcl.TComboBox
ExportPathLabel *vcl.TLabel
ExportPathPicker *vcl.TDirectoryEdit
BottomPanel *vcl.TPanel
LaunchButton *vcl.TBitBtn
TabSheet2 *vcl.TTabSheet
ServerListView *vcl.TListView
c1 *vcl.TListColumn
c2 *vcl.TListColumn
StatusBar *vcl.TStatusBar
p1 *vcl.TStatusPanel
p2 *vcl.TStatusPanel
}
var mainForm *TMainForm
func (f *TMainForm) OnFormCreate(sender vcl.IObject) {
f.SetWidth(800)
f.SetHeight(400)
f.Constraints().SetMinHeight(400) // to prevent wrong ordering of widgets for small windows sizes
f.SetPosition(types.PoDesktopCenter)
f.SetCaption("OMQ")
f.SetDoubleBuffered(true)
f.MainMenu = vcl.NewMainMenu(f)
f.ChangePasswordMenuItem = vcl.NewMenuItem(f)
f.MainMenu.Items().Add(f.ChangePasswordMenuItem)
f.ChangePasswordMenuItem.SetCaption("Изменить логин/пароль")
f.ChangePasswordMenuItem.SetBitmap(getImageBitmap("img/change_password.png"))
f.ChangePasswordMenuItem.SetOnClick(f.changePassword)
f.AboutMenuItem = vcl.NewMenuItem(f)
f.MainMenu.Items().Add(f.AboutMenuItem)
f.AboutMenuItem.SetCaption("О программе")
f.AboutMenuItem.SetBitmap(getImageBitmap("img/information.png"))
f.AboutMenuItem.SetOnClick(func(sender vcl.IObject) {
vcl.MessageDlg("Программа выгрузки результатов SQL-запросов с нескольких серверов баз данных Oracle.", types.MtInformation)
})
f.PageControl = vcl.NewPageControl(f)
f.PageControl.SetParent(f)
f.PageControl.SetAlign(types.AlClient)
f.TabSheet1 = vcl.NewTabSheet(f.PageControl)
f.TabSheet1.SetParent(f.PageControl)
f.TabSheet1.SetTabVisible(false)
f.GroupBox = vcl.NewGroupBox(f)
f.GroupBox.SetParent(f.TabSheet1)
f.GroupBox.SetAlign(types.AlClient)
f.GroupBox.SetCaption("Параметры запроса")
// TODO: добавить AutoSize
f.ConfigLabel = vcl.NewLabel(f)
f.ConfigLabel.SetParent(f.GroupBox)
f.ConfigLabel.SetCaption("Настройки серверов")
f.ConfigLabel.SetTop(0)
f.ConfigLabel.BorderSpacing().SetTop(8)
f.ConfigLabel.BorderSpacing().SetLeft(8)
f.ConfigLabel.BorderSpacing().SetRight(8)
f.ConfigLabel.SetAlign(types.AlTop)
f.ConfigComboBox = vcl.NewComboBox(f)
f.ConfigComboBox.SetParent(f.GroupBox)
f.ConfigComboBox.SetAlign(types.AlTop)
f.ConfigComboBox.BorderSpacing().SetTop(2)
f.ConfigComboBox.BorderSpacing().SetLeft(8)
f.ConfigComboBox.BorderSpacing().SetRight(8)
f.ConfigComboBox.SetTop(100)
f.ConfigComboBox.SetStyle(types.CsDropDownList)
f.SqlFileLabel = vcl.NewLabel(f)
f.SqlFileLabel.SetParent(f.GroupBox)
f.SqlFileLabel.SetCaption("SQL-скрипт")
f.SqlFileLabel.SetAlign(types.AlTop)
f.SqlFileLabel.BorderSpacing().SetTop(8)
f.SqlFileLabel.SetTop(200)
f.SqlFileLabel.BorderSpacing().SetLeft(8)
f.SqlFileLabel.BorderSpacing().SetRight(8)
f.SqlFileComboBox = vcl.NewComboBox(f)
f.SqlFileComboBox.SetParent(f.GroupBox)
f.SqlFileComboBox.SetAlign(types.AlTop)
f.SqlFileComboBox.BorderSpacing().SetTop(2)
f.SqlFileComboBox.BorderSpacing().SetLeft(8)
f.SqlFileComboBox.BorderSpacing().SetRight(8)
f.SqlFileComboBox.SetTop(300)
f.SqlFileComboBox.SetStyle(types.CsDropDownList)
f.ExportFormatLabel = vcl.NewLabel(f)
f.ExportFormatLabel.SetParent(f.GroupBox)
f.ExportFormatLabel.SetCaption("Формат выгрузки")
f.ExportFormatLabel.SetAlign(types.AlTop)
f.ExportFormatLabel.SetTop(400)
f.ExportFormatLabel.BorderSpacing().SetTop(8)
f.ExportFormatLabel.BorderSpacing().SetLeft(8)
f.ExportFormatLabel.BorderSpacing().SetRight(8)
f.ExportFormatComboBox = vcl.NewComboBox(f)
f.ExportFormatComboBox.SetParent(f.GroupBox)
f.ExportFormatComboBox.SetAlign(types.AlTop)
f.ExportFormatComboBox.BorderSpacing().SetTop(2)
f.ExportFormatComboBox.BorderSpacing().SetLeft(8)
f.ExportFormatComboBox.BorderSpacing().SetRight(8)
f.ExportFormatComboBox.SetTop(500)
f.ExportFormatComboBox.SetStyle(types.CsDropDownList)
f.ExportFormatComboBox.SetOnChange(f.OnExportFormatComboBoxChange)
f.CharsetLabel = vcl.NewLabel(f)
f.CharsetLabel.SetParent(f.GroupBox)
f.CharsetLabel.SetCaption("Кодировка CSV-файла")
f.CharsetLabel.SetAlign(types.AlTop)
f.CharsetLabel.SetTop(600)
f.CharsetLabel.BorderSpacing().SetTop(8)
f.CharsetLabel.BorderSpacing().SetLeft(8)
f.CharsetLabel.BorderSpacing().SetRight(8)
f.CharsetComboBox = vcl.NewComboBox(f)
f.CharsetComboBox.SetParent(f.GroupBox)
f.CharsetComboBox.SetAlign(types.AlTop)
f.CharsetComboBox.BorderSpacing().SetTop(2)
f.CharsetComboBox.BorderSpacing().SetLeft(8)
f.CharsetComboBox.BorderSpacing().SetRight(8)
f.CharsetComboBox.SetTop(700)
f.CharsetComboBox.SetStyle(types.CsDropDownList)
f.ExportPathLabel = vcl.NewLabel(f)
f.ExportPathLabel.SetParent(f.GroupBox)
f.ExportPathLabel.SetCaption("Путь сохранения результата")
f.ExportPathLabel.SetAlign(types.AlTop)
f.ExportPathLabel.SetTop(800)
f.ExportPathLabel.BorderSpacing().SetTop(8)
f.ExportPathLabel.BorderSpacing().SetLeft(8)
f.ExportPathLabel.BorderSpacing().SetRight(8)
f.ExportPathPicker = vcl.NewDirectoryEdit(f)
f.ExportPathPicker.SetParent(f.GroupBox)
f.ExportPathPicker.SetAlign(types.AlTop)
f.ExportPathPicker.BorderSpacing().SetTop(2)
f.ExportPathPicker.BorderSpacing().SetLeft(8)
f.ExportPathPicker.BorderSpacing().SetRight(8)
f.ExportPathPicker.SetTop(900)
f.ExportPathPicker.SetFlat(true)
f.BottomPanel = vcl.NewPanel(f)
f.BottomPanel.SetParent(f.TabSheet1)
f.BottomPanel.SetAlign(types.AlBottom)
f.BottomPanel.SetHeight(48)
f.BottomPanel.SetBevelOuter(types.BvNone)
f.LaunchButton = vcl.NewBitBtn(f)
f.LaunchButton.SetParent(f.BottomPanel)
f.LaunchButton.SetCaption("Запуск")
f.LaunchButton.SetAlign(types.AlRight)
f.LaunchButton.SetWidth(96)
f.LaunchButton.BorderSpacing().SetAround(8)
f.LaunchButton.SetOnClick(f.OnLaunchButtonClick)
f.LaunchButton.SetGlyph(getImageBitmap("img/bullet_go.png"))
f.TabSheet2 = vcl.NewTabSheet(f.PageControl)
f.TabSheet2.SetParent(f.PageControl)
f.TabSheet2.SetTabVisible(false)
f.ServerListView = vcl.NewListView(f)
f.ServerListView.SetParent(f.TabSheet2)
f.ServerListView.SetAlign(types.AlClient)
f.ServerListView.SetViewStyle(types.VsReport)
f.ServerListView.SetBorderStyle(types.BsNone)
f.ServerListView.SetReadOnly(true)
f.ServerListView.SetRowSelect(true)
f.c1 = f.ServerListView.Columns().Add()
f.c1.SetCaption("Сервер")
f.c1.SetAutoSize(true)
f.c2 = f.ServerListView.Columns().Add()
f.c2.SetCaption("Статус")
f.StatusBar = vcl.NewStatusBar(f)
f.StatusBar.SetParent(f)
f.StatusBar.SetSimplePanel(false)
f.p1 = f.StatusBar.Panels().Add()
f.p2 = f.StatusBar.Panels().Add()
f.SetOnResize(f.OnFormResize)
// Servers file list -------------------------------------------------------
configs, _ := filepath.Glob(filepath.Join(CONFIG_FILES_DIR, fmt.Sprintf("*.%s", CONFIG_FILE_EXT)))
for i := range configs {
configs[i] = strings.TrimSuffix(filepath.Base(configs[i]), "."+CONFIG_FILE_EXT)
}
for _, v := range configs {
f.ConfigComboBox.Items().Add(v)
}
if len(configs) > 0 {
f.ConfigComboBox.SetItemIndex(0)
}
// -------------------------------------------------------------------------
// SQL-files list ----------------------------------------------------------
files, _ := filepath.Glob(filepath.Join(SQL_FILES_DIR, fmt.Sprintf("*.%s", SQL_FILE_EXT)))
for i := range files {
files[i] = strings.TrimSuffix(filepath.Base(files[i]), "."+SQL_FILE_EXT)
}
for _, v := range files {
f.SqlFileComboBox.Items().Add(v)
}
if len(configs) > 0 {
f.SqlFileComboBox.SetItemIndex(0)
}
// -------------------------------------------------------------------------
// File formats ------------------------------------------------------------
for _, v := range []string{string(ExportFormatExcel), string(ExportFormatCsv), string(ExportFormatCsvZip), string(ExportFormatCsvZst)} {
f.ExportFormatComboBox.Items().Add(v)
}
f.ExportFormatComboBox.SetItemIndex(0)
// Charsets ----------------------------------------------------------------
for _, v := range []string{string(EncodingUtf8), string(EncodingWin1251)} {
f.CharsetComboBox.Items().Add(v)
}
f.CharsetComboBox.SetItemIndex(0)
f.OnExportFormatComboBoxChange(nil)
// -------------------------------------------------------------------------
}
func (f *TMainForm) OnFormResize(sender vcl.IObject) {
if f.Width() < 320 {
f.StatusBar.Panels().Items(0).SetWidth(f.Width() / 2)
} else {
f.StatusBar.Panels().Items(0).SetWidth(f.Width() - 160)
}
f.ServerListView.Columns().Items(1).SetWidth(
f.ServerListView.Width() - f.ServerListView.Columns().Items(0).Width())
}
func (f *TMainForm) OnLaunchButtonClick(sender vcl.IObject) {
f.MainMenu.Free()
job := &Job{
configFilePath: filepath.Join(CONFIG_FILES_DIR, f.ConfigComboBox.Text()) + "." + CONFIG_FILE_EXT,
scriptFilePath: filepath.Join(SQL_FILES_DIR, f.SqlFileComboBox.Text()) + "." + SQL_FILE_EXT,
exportFileFormat: ExportFormat(f.ExportFormatComboBox.Text()),
encoding: Encoding(f.CharsetComboBox.Text()),
exportPath: f.ExportPathPicker.Directory()}
err := job.init()
if err != nil {
vcl.MessageDlg(err.Error(), types.MtError)
return
}
for _, server := range job.config.Servers {
item := f.ServerListView.Items().Add()
item.SetCaption(server.Name)
item.SubItems().Add("")
}
f.PageControl.SetPageIndex(1)
go func() {
for !job.isFinished {
f.UpdateStatus(job)
time.Sleep(UI_UPDATE_PERIOD)
}
}()
go func() {
err = job.launch()
f.UpdateStatus(job)
if err != nil {
vcl.ThreadSync(func() {
vcl.MessageDlg(err.Error(), types.MtError)
f.Close()
})
} else {
vcl.ThreadSync(func() {
vcl.MessageDlg("Завершено.", types.MtInformation)
f.Close()
})
}
}()
}
func (f *TMainForm) OnExportFormatComboBoxChange(sender vcl.IObject) {
if slices.Contains([]string{string(ExportFormatCsv), string(ExportFormatCsvZip), string(ExportFormatCsvZst)}, f.ExportFormatComboBox.Text()) {
f.CharsetComboBox.SetEnabled(true)
} else {
f.CharsetComboBox.SetEnabled(false)
}
}
func (f *TMainForm) UpdateStatus(job *Job) {
vcl.ThreadSync(func() {
f.OnFormResize(nil)
f.StatusBar.Panels().Items(0).SetText(job.status)
f.StatusBar.Panels().Items(1).SetText(fmt.Sprintf("%d строк", job.exportedRows))
for i, v := range job.config.Servers {
s := []string{v.status}
if v.err != nil {
s = append(s, v.err.Error())
}
f.ServerListView.Items().Item(int32(i)).SubItems().SetText(strings.Join(s, ": "))
}
})
}
func (f *TMainForm) changePassword(sender vcl.IObject) {
changePasswordForm := new(TConfigEditorForm)
vcl.Application.CreateForm(&changePasswordForm)
if changePasswordForm.ShowModal() != types.IdOK {
return
}
newLogin := changePasswordForm.loginEdit.Text()
newPassword := changePasswordForm.passwordEdit.Text()
changePasswordForm.Free()
configFilePath := filepath.Join(CONFIG_FILES_DIR, f.ConfigComboBox.Text()) + "." + CONFIG_FILE_EXT
config, err := loadConfig(configFilePath)
if err != nil {
vcl.MessageDlg(err.Error(), types.MtError)
return
}
for _, server := range config.Servers {
server.Login = newLogin
server.Password = newPassword
}
file, err := os.Create(configFilePath)
if err != nil {
vcl.MessageDlg(err.Error(), types.MtError)
return
}
err = toml.NewEncoder(file).Encode(config)
if err != nil {
vcl.MessageDlg(err.Error(), types.MtError)
file.Close()
return
}
err = file.Close()
if err != nil {
vcl.MessageDlg(err.Error(), types.MtError)
return
}
vcl.MessageDlg("Логин/пароль успешно изменены.", types.MtInformation)
}