394 lines
12 KiB
Go
394 lines
12 KiB
Go
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(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()),
|
||
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)
|
||
}
|