omq/ui_main_form.go

394 lines
12 KiB
Go
Raw Normal View History

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
2024-03-05 21:41:51 +05:00
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)
2024-03-05 21:41:51 +05:00
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 ------------------------------------------------------------
2024-03-09 21:54:26 +05:00
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(EncodingWin1251), string(EncodingUtf8)} {
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()),
2024-03-05 21:41:51 +05:00
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) {
2024-03-09 21:54:26 +05:00
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)
}