diff --git a/README.md b/README.md
index 3199fe9..8b11ac6 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,10 @@
Sqlite-gui is a lightweight Windows GUI for [SQLite](https://www.sqlite.org/index.html) powered by C++, WinAPI and [Code::Blocks 17](http://www.codeblocks.org/).
-|[**Download latest version**](https://github.com/little-brother/sqlite-gui/releases/latest)|
+|[**Download the latest version**](https://github.com/little-brother/sqlite-gui/releases/latest)|
|-------------------------------------------------------------------------------------------|
-![View](resources/image.webp)
+![View](resources/demo.webp)
### Features
@@ -15,17 +15,19 @@ Sqlite-gui is a lightweight Windows GUI for [SQLite](https://www.sqlite.org/inde
* Database comparison
* Search text in the whole database
* [Workflow manager](https://github.com/little-brother/sqlite-wf) (ETL)
-* Quick data references ([video](https://youtu.be/XL1_lFhzLKo))
-* Terminal mode
-* Charts
+* [Quick data references](https://github.com/little-brother/sqlite-gui/wiki#quick-references) ([video](https://youtu.be/XL1_lFhzLKo))
+* [Terminal mode](https://raw.githubusercontent.com/little-brother/sqlite-gui/master/resources/terminal.webp)
+* [Charts](https://github.com/little-brother/sqlite-gui/wiki#charts)
+* [Query parameters](https://github.com/little-brother/sqlite-gui/wiki#query-parameters)
* Data generator
-* Most usefull extensions are included
+* [Extension pack](https://github.com/little-brother/sqlite-gui/wiki#extensions)
* Demo database "Bookstore" for beginners
* Does not require installation
### Cons
* Only utf-8 is supported
* NULL is displayed as an empty string and an empty string is set to NULL when data is edit
+* The application is a single threaded. Therefore, the interface freeze on long operations
If you like the project, press the like-button [here](https://alternativeto.net/software/sqlite-gui/) or write something in a [Reddit](https://www.reddit.com/r/sqlite/comments/iaao8x/a_new_lightweight_sqlite_tool_for_windows/) topic to support it.
If you have any problems, comments or suggestions, check [Wiki](https://github.com/little-brother/sqlite-gui/wiki) or just let me know lb.im@yandex.ru.
diff --git a/extensions/ora.c b/extensions/ora.c
index 049fa48..32f7d2c 100644
--- a/extensions/ora.c
+++ b/extensions/ora.c
@@ -17,14 +17,19 @@
md5(str)
Calculate md5 checksum
+
+ strpart(str, delimiter, partno)
+ Returns substring for a delimiter and a part number
+ select strpart('ab-cd-ef', '-', 2) --> 'cd'
+ select strpart('20.01.2021', '.', 3) --> 2021
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
-#include
#include
#include
-#include
-#include
+
+typedef unsigned char UINT8;
+typedef unsigned int UINT;
static void rownum(sqlite3_context *ctx, int argc, sqlite3_value **argv){
int *pCounter = (int*)sqlite3_get_auxdata(ctx, 0);
@@ -167,18 +172,18 @@ const UINT r[] = {
#define LEFTROTATE(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
-void to_bytes(UINT val, UINT8 *bytes) {
+static void to_bytes(UINT val, UINT8 *bytes) {
bytes[0] = (UINT8) val;
bytes[1] = (UINT8) (val >> 8);
bytes[2] = (UINT8) (val >> 16);
bytes[3] = (UINT8) (val >> 24);
}
-UINT to_int32(const UINT8 *bytes) {
+static UINT to_int32(const UINT8 *bytes) {
return (UINT) bytes[0] | ((UINT) bytes[1] << 8) | ((UINT) bytes[2] << 16) | ((UINT) bytes[3] << 24);
}
-void _md5(const UINT8 *initial_msg, size_t initial_len, UINT8 *digest) {
+static void _md5(const UINT8 *initial_msg, size_t initial_len, UINT8 *digest) {
UINT h0, h1, h2, h3;
UINT8 *msg = NULL;
@@ -248,23 +253,57 @@ void _md5(const UINT8 *initial_msg, size_t initial_len, UINT8 *digest) {
to_bytes(h3, digest + 12);
}
+char const hex_chars[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
static void md5 (sqlite3_context *ctx, int argc, sqlite3_value **argv) {
- UINT8 r[16];
- _md5(sqlite3_value_text(argv[0]), strlen(sqlite3_value_text(argv[0])), r);
+ UINT8 res[16];
+ _md5(sqlite3_value_text(argv[0]), strlen(sqlite3_value_text(argv[0])), res);
+
+ char buf[33];
+ for(int i = 0; i < 16; i++) {
+ char byte = res[i];
+ buf[2 * i] = hex_chars[(byte & 0xF0) >> 4];
+ buf[2 * i + 1] = hex_chars[(byte & 0x0F) >> 0];
+ }
+ buf[32] = 0;
+
+ sqlite3_result_text(ctx, buf, -1, SQLITE_TRANSIENT);
+}
- char buf[17];
- sprintf(buf, "%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x", r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]);
- sqlite3_result_text(ctx, buf, -1, SQLITE_TRANSIENT);
+static void strpart (sqlite3_context *ctx, int argc, sqlite3_value **argv) {
+ const char* instr = sqlite3_value_text(argv[0]);
+ const char* delim = sqlite3_value_text(argv[1]);
+ int no = sqlite3_value_int(argv[2]);
+
+ if (no < 1) {
+ sqlite3_result_null(ctx);
+ return;
+ }
+
+ char str[strlen(instr) + 1];
+ strcpy(str, instr);
+
+ char *ptr = strtok(str, delim);
+ int curr = 0;
+ while (ptr != NULL && curr < no - 1) {
+ ptr = strtok(NULL, delim);
+ curr++;
+ }
+
+ if (ptr)
+ sqlite3_result_text(ctx, ptr, -1, SQLITE_TRANSIENT);
+ else
+ sqlite3_result_null(ctx);
}
__declspec(dllexport) int sqlite3_ora_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) {
- int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
return SQLITE_OK == sqlite3_create_function(db, "rownum", 1, SQLITE_UTF8, 0, rownum, 0, 0) &&
SQLITE_OK == sqlite3_create_function(db, "concat", -1, SQLITE_UTF8, 0, concat, 0, 0) &&
SQLITE_OK == sqlite3_create_function(db, "decode", -1, SQLITE_UTF8, 0, decode, 0, 0) &&
SQLITE_OK == sqlite3_create_function(db, "crc32", 1, SQLITE_UTF8, 0, crc32, 0, 0) &&
- SQLITE_OK == sqlite3_create_function(db, "md5", 1, SQLITE_UTF8, 0, md5, 0, 0) ?
+ SQLITE_OK == sqlite3_create_function(db, "md5", 1, SQLITE_UTF8, 0, md5, 0, 0) &&
+ SQLITE_OK == sqlite3_create_function(db, "strpart", 3, SQLITE_UTF8, 0, strpart, 0, 0) ?
SQLITE_OK : SQLITE_ERROR;
}
\ No newline at end of file
diff --git a/resources/btn_add.bmp b/resources/btn_add.bmp
deleted file mode 100644
index bf62cbc..0000000
Binary files a/resources/btn_add.bmp and /dev/null differ
diff --git a/resources/btn_delete.bmp b/resources/btn_delete.bmp
deleted file mode 100644
index e822891..0000000
Binary files a/resources/btn_delete.bmp and /dev/null differ
diff --git a/resources/btn_refresh.bmp b/resources/btn_refresh.bmp
deleted file mode 100644
index 7a789fc..0000000
Binary files a/resources/btn_refresh.bmp and /dev/null differ
diff --git a/resources/charts.webp b/resources/charts.webp
new file mode 100644
index 0000000..326ea2f
Binary files /dev/null and b/resources/charts.webp differ
diff --git a/resources/demo.webp b/resources/demo.webp
new file mode 100644
index 0000000..5dc9b0a
Binary files /dev/null and b/resources/demo.webp differ
diff --git a/resources/image.webp b/resources/image.webp
deleted file mode 100644
index 8eeb490..0000000
Binary files a/resources/image.webp and /dev/null differ
diff --git a/resources/terminal.webp b/resources/terminal.webp
new file mode 100644
index 0000000..0159c19
Binary files /dev/null and b/resources/terminal.webp differ
diff --git a/resources/toolbar_data.bmp b/resources/toolbar_data.bmp
new file mode 100644
index 0000000..076920c
Binary files /dev/null and b/resources/toolbar_data.bmp differ
diff --git a/sqlite-gui.cbp b/sqlite-gui.cbp
index 8305d7a..81e938c 100644
--- a/sqlite-gui.cbp
+++ b/sqlite-gui.cbp
@@ -40,8 +40,11 @@
+
+
+
diff --git a/sqlite-gui.depend b/sqlite-gui.depend
index 2466e52..c0f2c3f 100644
--- a/sqlite-gui.depend
+++ b/sqlite-gui.depend
@@ -22,20 +22,20 @@
1562796420 d:\codes\sqlite-gui\sqlite3.h
-1610099075 source:d:\codes\sqlite-gui\src\resource.rc
+1611058507 source:d:\codes\sqlite-gui\src\resource.rc
"resource.h"
-1609978095 d:\codes\sqlite-gui\src\resource.h
+1610981283 d:\codes\sqlite-gui\src\resource.h
-1609924139 source:d:\codes\sqlite-gui\src\prefs.cpp
+1611090146 source:d:\codes\sqlite-gui\src\prefs.cpp
"prefs.h"
"sqlite3.h"
-1602007947 d:\codes\sqlite-gui\src\prefs.h
+1611089165 d:\codes\sqlite-gui\src\prefs.h
@@ -43,7 +43,7 @@
1583506689 d:\codes\sqlite-gui\src\sqlite3.h
-1610058432 source:d:\codes\sqlite-gui\src\main.cpp
+1611003745 source:d:\codes\sqlite-gui\src\main.cpp
"global.h"
"missing.h"
"resource.h"
@@ -57,19 +57,19 @@
1583970008 d:\codes\sqlite-gui\src\main.h
-1605587592 d:\codes\sqlite-gui\src\utils.h
+1610994001 d:\codes\sqlite-gui\src\utils.h
"sqlite3.h"
-1605587816 source:d:\codes\sqlite-gui\src\utils.cpp
+1610994064 source:d:\codes\sqlite-gui\src\utils.cpp
"utils.h"
-1610099913 source:d:\codes\sqlite-gui\src\tools.cpp
+1611001401 source:d:\codes\sqlite-gui\src\tools.cpp
"global.h"
"missing.h"
"resource.h"
@@ -78,7 +78,7 @@
"dialogs.h"
"prefs.h"
-1610048754 d:\codes\sqlite-gui\src\global.h
+1610376139 d:\codes\sqlite-gui\src\global.h
@@ -90,20 +90,22 @@
+ "missing.h"
"sqlite3.h"
1605592862 d:\codes\sqlite-gui\src\tools.h
-1609944947 d:\codes\sqlite-gui\src\dialogs.h
+1610981781 d:\codes\sqlite-gui\src\dialogs.h
-1610099817 source:d:\codes\sqlite-gui\src\dialogs.cpp
+1611092472 source:d:\codes\sqlite-gui\src\dialogs.cpp
"resource.h"
"global.h"
"prefs.h"
"utils.h"
"dialogs.h"
+ "tools.h"
1606840569 d:\codes\sqlite-gui\include\sqlite3.h
@@ -116,7 +118,7 @@
"oaidl.h"
"ocidl.h"
-1609795113 d:\codes\sqlite-gui\src\missing.h
+1610377907 d:\codes\sqlite-gui\src\missing.h
1595499199 c:\mingw\include\windows.h
diff --git a/sqlite-gui.layout b/sqlite-gui.layout
index e453ada..2352c7d 100644
--- a/sqlite-gui.layout
+++ b/sqlite-gui.layout
@@ -2,74 +2,74 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/src/dialogs.cpp b/src/dialogs.cpp
index a449764..38f85f7 100644
--- a/src/dialogs.cpp
+++ b/src/dialogs.cpp
@@ -1,13 +1,15 @@
-#include"resource.h"
-#include"global.h"
+#include "resource.h"
+#include "global.h"
#include "prefs.h"
#include "utils.h"
-#include"dialogs.h"
+#include "dialogs.h"
+#include "tools.h"
namespace dialogs {
- WNDPROC cbOldEditDataEdit, cbOldAddTableCell;
+ WNDPROC cbOldEditDataEdit, cbOldAddTableCell, cbOldHeaderEdit;
LRESULT CALLBACK cbNewEditDataEdit(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK cbNewAddTableCell(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+ LRESULT CALLBACK cbNewFilterEdit(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK cbDlgEditDataValue (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
bool ListView_UpdateCell(HWND hListWnd, int rowNo, int colNo, TCHAR* value16);
@@ -18,12 +20,6 @@ namespace dialogs {
bool isRequireHighligth = false;
bool isRequireParenthesisHighligth = false;
- HBITMAP hButtonIcons [] = {
- (HBITMAP)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDB_BTN_ADD), IMAGE_BITMAP, 16, 16, LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS),
- (HBITMAP)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDB_BTN_DELETE), IMAGE_BITMAP, 16, 16, LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS),
- (HBITMAP)LoadImage(GetModuleHandle(0), MAKEINTRESOURCE(IDB_BTN_REFRESH), IMAGE_BITMAP, 16, 16, LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS)
- };
-
BOOL CALLBACK cbDlgAddEdit (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_INITDIALOG: {
@@ -504,7 +500,6 @@ namespace dialogs {
break;
case WM_COMMAND: {
-
if (HIWORD(wParam) == EN_CHANGE && (HWND)lParam == GetDlgItem(hWnd, IDC_DLG_QUERYFILTER) && (HWND)lParam == GetFocus()) {
KillTimer(hWnd, IDT_EDIT_DATA);
SetTimer(hWnd, IDT_EDIT_DATA, 300, NULL);
@@ -545,7 +540,7 @@ namespace dialogs {
HWND hFilterWnd = GetDlgItem(hWnd, IDC_DLG_QUERYFILTER);
int size = GetWindowTextLength(hFilterWnd);
- TCHAR* filter16 = new TCHAR[size + 1]{0};
+ TCHAR filter16[size + 1]{0};
GetWindowText(hFilterWnd, filter16, size + 1);
int idx = GetWindowLong(hWnd, GWL_USERDATA);
@@ -588,7 +583,7 @@ namespace dialogs {
ListView_SetItemState (hListWnd, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F);
delete [] filter8;
- delete [] filter16;
+ return true;
}
break;
@@ -601,7 +596,6 @@ namespace dialogs {
return false;
}
- char filterQuery8[MAX_TEXT_LENGTH]{0};
BOOL CALLBACK cbDlgEditData (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_INITDIALOG: {
@@ -639,88 +633,120 @@ namespace dialogs {
}
sqlite3_finalize(stmt);
}
+ HWND hListWnd = GetDlgItem(hWnd, IDC_DLG_QUERYLIST);
+ HWND hHeader = ListView_GetHeader(hListWnd);
+ LONG_PTR styles = GetWindowLongPtr(hHeader, GWL_STYLE);
+ SetWindowLongPtr(hHeader, GWL_STYLE, styles | HDS_FILTERBAR);
+
+ bool isTable = false;
+ sprintf(query8, "select lower(type) = 'table' from %s.sqlite_master where tbl_name = \"%s\" and type in ('view', 'table')", schema8, tablename8);
+ if ((SQLITE_OK == sqlite3_prepare_v2(db, query8, -1, &stmt, 0)) && (SQLITE_ROW == sqlite3_step(stmt)))
+ isTable = sqlite3_column_int(stmt, 0);
+ sqlite3_finalize(stmt);
+ SetWindowLong(hWnd, GWL_USERDATA, +isTable);
- HWND hFilterWnd = GetDlgItem(hWnd, IDC_DLG_QUERYFILTER);
SendMessage(hWnd, WMU_UPDATE_DATA, 0 , 0);
- SetFocus(hFilterWnd);
- sprintf(filterQuery8,
- "select '\"***\" || coalesce(' || group_concat(name, ', \"\") || \"***\" || coalesce(') || ', \"\") || \"***\"', "\
- "(select type from %s.sqlite_master where tbl_name = \"%s\" and type in ('view', 'table')) type from pragma_table_info t where schema = '%s' and arg = '%s' and upper(t.type) <> 'BLOB'",
- schema8, tablename8, schema8, tablename8);
+ TBBUTTON tbTableButtons [] = {
+ {2, IDM_ROW_REFRESH, TBSTATE_ENABLED, TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE, {0}, 0L, (INT_PTR)TEXT("Refresh")},
+ {0, IDM_ROW_ADD, TBSTATE_ENABLED, TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE, {0}, 0L, (INT_PTR)TEXT("Add")},
+ {1, IDM_ROW_DELETE, TBSTATE_ENABLED, TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE, {0}, 0L, (INT_PTR)TEXT("Delete")},
+ {3, IDM_GENERATE_DATA, TBSTATE_ENABLED, TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE, {0}, 0L, (INT_PTR)TEXT("Generate data")},
+ {-1, IDM_LAST_SEPARATOR, TBSTATE_ENABLED, TBSTYLE_SEP, {0}, 0L, 0}
+ };
+
+ TBBUTTON tbViewButtons [] = {
+ {2, IDM_ROW_REFRESH, TBSTATE_ENABLED, TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE, {0}, 0L, (INT_PTR)TEXT("Refresh")},
+ {-1, IDM_LAST_SEPARATOR, TBSTATE_ENABLED, TBSTYLE_SEP, {0}, 0L, 0}
+ };
+
+ int btnCount = isTable ? sizeof(tbTableButtons)/sizeof(tbTableButtons[0]) : sizeof(tbViewButtons)/sizeof(tbViewButtons[0]);
+ HWND hToolbarWnd = CreateToolbarEx (hWnd, WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | TBSTYLE_LIST, IDC_DLG_TOOLBAR, 0, NULL, 0,
+ isTable ? tbTableButtons : tbViewButtons, btnCount,
+ 0, 0, 0, 0, sizeof (TBBUTTON));
+ SendMessage(hToolbarWnd, TB_SETIMAGELIST,0, (LPARAM)ImageList_LoadBitmap(GetModuleHandle(0), MAKEINTRESOURCE(IDB_TOOLBAR_DATA), 0, 0, RGB(255,255,255)));
- bool isTable = false;
- if ((SQLITE_OK == sqlite3_prepare_v2(db, filterQuery8, -1, &stmt, 0)) && (SQLITE_ROW == sqlite3_step(stmt))) {
- sprintf(filterQuery8, "select *, %s from \"%s\".\"%s\" where %s like \"***%%%%%%s%%%%***\"",
- hasRowid ? "rowid" : (char*)GetProp(hWnd, TEXT("MD5KEYS8")), schema8, tablename8, sqlite3_column_text(stmt, 0));
- isTable = strcmp((char*)sqlite3_column_text(stmt, 1), "table") == 0;
- } else {
- showDbError(hWnd);
+ RECT rc{0};
+ SendMessage(hToolbarWnd, TB_GETRECT, IDM_LAST_SEPARATOR, (LPARAM)&rc);
+ HWND hFilterWnd = CreateWindowEx(0L, WC_EDIT, NULL, WS_CHILD | WS_BORDER | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL, rc.right, 2, 180, 19, hToolbarWnd, (HMENU) IDC_DLG_FILTER, GetModuleHandle(0), 0);
+ SendMessage(hFilterWnd, WM_SETFONT, (LPARAM)SendMessage(hToolbarWnd, WM_GETFONT, 0, 0), true);
+ cbOldHeaderEdit = (WNDPROC)SetWindowLong(hFilterWnd, GWL_WNDPROC, (LONG)cbNewFilterEdit);
+
+ int colCount = Header_GetItemCount(hHeader);
+ HFONT hFont = (HFONT)SendMessage(hListWnd, WM_GETFONT, 0, 0);
+ for (int i = 0; i < colCount; i++) {
+ RECT rc;
+ Header_GetItemRect(hHeader, i, &rc);
+ HWND hEdit = CreateWindowEx(WS_EX_TOPMOST, WC_EDIT, NULL, ES_CENTER | ES_AUTOHSCROLL | WS_VISIBLE | WS_CHILD | WS_TABSTOP, 0, 0, 0, 0, hHeader, (HMENU)(IDC_HEADER_EDIT + i), GetModuleHandle(0), NULL);
+ SendMessage(hEdit, WM_SETFONT, (LPARAM)hFont, true);
+ cbOldHeaderEdit = (WNDPROC)SetWindowLong(hEdit, GWL_WNDPROC, (LONG)cbNewFilterEdit);
+ CreateWindowEx(WS_EX_TOPMOST, WC_STATIC, NULL, WS_VISIBLE | WS_CHILD | SS_WHITEFRAME, 0, 0, 0, 0, hHeader, (HMENU)(IDC_HEADER_STATIC + i), GetModuleHandle(0), NULL);
}
- sqlite3_finalize(stmt);
- SetWindowLong(hWnd, GWL_USERDATA, +isTable);
- ShowWindow(GetDlgItem(hWnd, IDC_DLG_ROW_ADD), isTable ? SW_SHOW : SW_HIDE);
+ int* widths = new int[colCount]{0};
+ for (int i = 0; i < colCount; i++)
+ widths[i] = ListView_GetColumnWidth(hListWnd, i);
+ SetProp(hWnd, TEXT("WIDTHS"), (HANDLE)widths);
SetWindowPos(hWnd, 0, prefs::get("x") + 40, prefs::get("y") + 80, prefs::get("width") - 80, prefs::get("height") - 120, SWP_NOZORDER);
ShowWindow (hWnd, prefs::get("maximized") == 1 ? SW_MAXIMIZE : SW_SHOW);
-
- HWND hBtnWnd = GetDlgItem(hWnd, IDC_DLG_ROW_ADD);
- SendMessage(hBtnWnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hButtonIcons[0]);
- hBtnWnd = GetDlgItem(hWnd, IDC_DLG_ROW_DEL);
- SendMessage(hBtnWnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hButtonIcons[1]);
- hBtnWnd = GetDlgItem(hWnd, IDC_DLG_REFRESH);
- SendMessage(hBtnWnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hButtonIcons[2]);
- cbOldResultList = (WNDPROC)SetWindowLong(GetDlgItem(hWnd, IDC_DLG_QUERYLIST), GWL_WNDPROC, (LONG)cbNewResultList);
- }
- break;
-
- case WM_TIMER: {
- KillTimer(hWnd, IDT_EDIT_DATA);
- SendMessage(hWnd, WMU_UPDATE_DATA, 0, 0);
}
break;
case WM_SIZE: {
- bool isTable = GetWindowLong(hWnd, GWL_USERDATA) == 1;
- HWND hRefreshBtn = GetDlgItem(hWnd, IDC_DLG_REFRESH);
HWND hListWnd = GetDlgItem(hWnd, IDC_DLG_QUERYLIST);
- HWND hFilterWnd = GetDlgItem(hWnd, IDC_DLG_QUERYFILTER);
+ HWND hToolbarWnd = GetDlgItem(hWnd, IDC_DLG_TOOLBAR);
- RECT rc;
+ SendMessage(hToolbarWnd, WM_SIZE, 0, 0);
+ RECT rc, rc2, rc3;
GetClientRect(hWnd, &rc);
- int w = isTable ? 44 : 0;
- SetWindowPos(hRefreshBtn, 0, rc.right - rc.left - 21, 0, 20, 20, SWP_NOZORDER);
- SetWindowPos(hFilterWnd, 0, w, 0, rc.right - rc.left - 0 - w - 22, 20, SWP_NOZORDER);
- SetWindowPos(hListWnd, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top - 21, SWP_NOZORDER | SWP_NOMOVE);
+ GetClientRect(hToolbarWnd, &rc2);
+ SetWindowPos(hListWnd, 0, 0, rc2.bottom + 2, rc.right - rc.left, rc.bottom - rc.top - 28, SWP_NOZORDER);
+
+ HWND hFilterWnd = GetDlgItem(hToolbarWnd, IDC_DLG_FILTER);
+ GetWindowRect(hFilterWnd, &rc3);
+ POINT p{rc3.left, rc3.bottom};
+ ScreenToClient(hToolbarWnd, &p);
+ SetWindowPos(hFilterWnd, 0, 0, 0, rc.right - p.x, 19, SWP_NOZORDER | SWP_NOMOVE);
}
break;
case WMU_UPDATE_DATA: {
HWND hListWnd = GetDlgItem(hWnd, IDC_DLG_QUERYLIST);
- HWND hFilterWnd = GetDlgItem(hWnd, IDC_DLG_QUERYFILTER);
+ HWND hHeader = ListView_GetHeader(hListWnd);
bool isTable = GetWindowLong(hWnd, GWL_USERDATA) == 1;
bool hasRowid = GetProp(hWnd, TEXT("HASROWID"));
+ HWND hFilterWnd = GetDlgItem(GetDlgItem(hWnd, IDC_DLG_TOOLBAR),IDC_DLG_FILTER);
int size = GetWindowTextLength(hFilterWnd);
TCHAR filter16[size + 1]{0};
GetWindowText(hFilterWnd, filter16, size + 1);
- char* filter8 = utils::utf16to8(filter16);
+ SetWindowText(hWnd, TEXT("Fetching data..."));
+
char* tablename8 = (char*)GetProp(hWnd, TEXT("TABLENAME8"));
char* schema8 = (char*)GetProp(hWnd, TEXT("SCHEMA8"));
+ char* md5keys = (char*)GetProp(hWnd, TEXT("MD5KEYS8"));
- char query8[MAX_TEXT_LENGTH]{0};
- sprintf(query8, "select *, %s rowid from \"%s\".\"%s\" t %s", hasRowid ? "rowid" : (char*)GetProp(hWnd, TEXT("MD5KEYS8")), schema8, tablename8, filter8 && strlen(filter8) ? filter8 : "");
-
- if (!isQueryValid(query8)) {
- sprintf(query8, "select *, %s rowid from \"%s\".\"%s\" where %s", hasRowid ? "rowid" : (char*)GetProp(hWnd, TEXT("MD5KEYS8")), schema8, tablename8, filter8);
+ TCHAR where16[MAX_TEXT_LENGTH]{0};
+ _tcscat(where16, TEXT("where ("));
+ _tcscat(where16, _tcslen(filter16) ? filter16 : TEXT("1 = 1"));
+ _tcscat(where16, TEXT(") "));
+
+ for (int colNo = 1; colNo < Header_GetItemCount(hHeader); colNo++) {
+ if (GetWindowTextLength(GetDlgItem(hHeader, IDC_HEADER_EDIT + colNo)) > 0) {
+ TCHAR colname16[256]{0};
+ Header_GetItemText(hHeader, colNo, colname16, 255);
+ _tcscat(where16, TEXT(" and \""));
+ _tcscat(where16, colname16);
+ _tcscat(where16, TEXT("\" like '%' || ? || '%' "));
+ }
- // "where 4" or "where true" are valid filters
- bool isValid = isQueryValid(query8);
- if (!isValid || (isValid && strchr(filter8, ' ') == NULL))
- sprintf(query8, filterQuery8, filter8);
}
+ char* where8 = utils::utf16to8(where16);
+
+ char query8[MAX_TEXT_LENGTH]{0};
+ sprintf(query8, "select *, %s rowid from \"%s\".\"%s\" t %s", hasRowid ? "rowid" : md5keys, schema8, tablename8, where8 && strlen(where8) ? where8 : "");
sqlite3_stmt *stmt;
if (SQLITE_OK == sqlite3_prepare_v2(db, query8, -1, &stmt, 0)) {
@@ -732,9 +758,30 @@ namespace dialogs {
SetProp(hWnd, TEXT("BLOBS"), (HANDLE)types);
}
+ int bindNo = 0;
+ for (int colNo = 1; (colNo < colCount) && strlen(where8); colNo++) {
+ HWND hEdit = GetDlgItem(hHeader, IDC_HEADER_EDIT + colNo);
+ int size = GetWindowTextLength(hEdit);
+ if (size > 0) {
+
+ TCHAR value16[size + 1]{0};
+ GetWindowText(hEdit, value16, size + 1);
+ char* value8 = utils::utf16to8(value16);
+ sqlite3_bind_text(stmt, bindNo + 1, value8, strlen(value8), SQLITE_TRANSIENT);
+ delete [] value8;
+ bindNo++;
+ }
+ }
+
+ ShowWindow(hListWnd, SW_HIDE);
int rowCount = ListView_SetData(hListWnd, stmt, true);
ListView_SetColumnWidth(hListWnd, colCount, 0); // last column is rowid
+ int* widths = (int*)GetProp(hWnd, TEXT("WIDTHS"));
+ for (int i = 0; i < colCount && widths; i++)
+ ListView_SetColumnWidth(hListWnd, i, widths[i]);
+ ShowWindow(hListWnd, SW_SHOW);
+
TCHAR buf[256]{0};
_stprintf(buf, TEXT("%s \"%s\" [%s%i rows]"), isTable ? TEXT("Table") : TEXT("View"), editTableData16, rowCount < 0 ? TEXT("Show only first ") : TEXT(""), abs(rowCount));
SetWindowText(hWnd, buf);
@@ -744,8 +791,74 @@ namespace dialogs {
}
ListView_SetItemState(hListWnd, 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
+ SendMessage(hWnd, WMU_SET_CURRENT_CELL, 0, 1);
- delete [] filter8;
+ delete [] where8;
+ PostMessage(hWnd, WMU_UPDATE_COLSIZE, 0, 0);
+ InvalidateRect(hHeader, NULL, true);
+ return true;
+ }
+ break;
+
+ case WMU_UPDATE_COLSIZE: {
+ HWND hListWnd = GetDlgItem(hWnd, IDC_DLG_QUERYLIST);
+ HWND hHeader = ListView_GetHeader(hListWnd);
+ SendMessage(hHeader, WM_SIZE, 0, 0);
+ for (int i = 0; i < Header_GetItemCount(hHeader); i++) {
+ RECT rc;
+ Header_GetItemRect(hHeader, i, &rc);
+ SetWindowPos(GetDlgItem(hHeader, IDC_HEADER_STATIC + i), 0, rc.left + 1, rc.top + 20, rc.right - rc.left - 2, 2, SWP_NOZORDER);
+ SetWindowPos(GetDlgItem(hHeader, IDC_HEADER_EDIT + i), 0, rc.left + 1, rc.top + 20 + 2, rc.right - rc.left - 2, rc.bottom - rc.top - 21 - 2, SWP_NOZORDER);
+ }
+ }
+ break;
+
+ case WMU_SET_CURRENT_CELL: {
+ HWND hListWnd = GetDlgItem(hWnd, IDC_DLG_QUERYLIST);
+ RECT rect;
+ ListView_GetSubItemRect(hListWnd, currCell.iItem, currCell.iSubItem, LVIR_BOUNDS, &rect);
+ InvalidateRect(hListWnd, &rect, true);
+
+ currCell = {hListWnd, (int)wParam, (int)lParam};
+
+ ListView_GetSubItemRect(hListWnd, currCell.iItem, currCell.iSubItem, LVIR_BOUNDS, &rect);
+ InvalidateRect(hListWnd, &rect, true);
+ SetFocus(hListWnd);
+ }
+ break;
+
+ case WMU_SYNC_CURRENT_CELL: {
+ HWND hListWnd = GetDlgItem(hWnd, IDC_DLG_QUERYLIST);
+ int rowNo = ListView_GetNextItem(hListWnd, -1, LVNI_SELECTED);
+ SendMessage(hWnd, WMU_SET_CURRENT_CELL, rowNo, currCell.iSubItem);
+ }
+ break;
+
+ case WMU_EDIT_VALUE: {
+ HWND hListWnd = GetDlgItem(hWnd, IDC_DLG_QUERYLIST);
+ bool withText = wParam != 0;
+
+ RECT rect;
+ ListView_GetSubItemRect(hListWnd, currCell.iItem, currCell.iSubItem, LVIR_BOUNDS, &rect);
+ int h = rect.bottom - rect.top;
+ int w = ListView_GetColumnWidth(hListWnd, currCell.iSubItem);
+
+ TCHAR buf[MAX_TEXT_LENGTH];
+ ListView_GetItemText(hListWnd, currCell.iItem, currCell.iSubItem, buf, MAX_TEXT_LENGTH);
+
+ if (_tcscmp(buf, TEXT("(BLOB)")) == 0 || currCell.iSubItem < 1)
+ return true;
+
+ HWND hEdit = CreateWindowEx(0, WC_EDIT, withText ? buf : NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, rect.left, rect.top, w, h, hListWnd, 0, GetModuleHandle(NULL), NULL);
+ SetWindowLong(hEdit, GWL_USERDATA, MAKELPARAM(currCell.iItem, currCell.iSubItem));
+ int end = GetWindowTextLength(hEdit);
+ SendMessage(hEdit, EM_SETSEL, end, end);
+ SendMessage(hEdit, WM_SETFONT, (LPARAM)hDefFont, true);
+ cbOldEditDataEdit = (WNDPROC)SetWindowLong(hEdit, GWL_WNDPROC, (LONG)cbNewEditDataEdit);
+ SetFocus(hEdit);
+
+ if (!withText)
+ keybd_event(lParam, 0, 0, 0);
}
break;
@@ -762,7 +875,8 @@ namespace dialogs {
if (pHdr->code == (DWORD)NM_RCLICK && pHdr->hwndFrom == hListWnd) {
NMITEMACTIVATE* ia = (LPNMITEMACTIVATE) lParam;
- currCell = {hListWnd, ia->iItem, ia->iSubItem};
+ SendMessage(hWnd, WMU_SET_CURRENT_CELL, ia->iItem, ia->iSubItem);
+
POINT p;
GetCursorPos(&p);
@@ -785,28 +899,123 @@ namespace dialogs {
return ListView_ShowRef(hListWnd, ia->iItem, ia->iSubItem);
}
- if (pHdr->code == (DWORD)NM_DBLCLK && pHdr->hwndFrom == hListWnd && !isTable) {
+ if (!isTable && pHdr->code == (DWORD)NM_DBLCLK && pHdr->hwndFrom == hListWnd) {
NMITEMACTIVATE* ia = (LPNMITEMACTIVATE) lParam;
if (ia->iItem != -1)
SendMessage(hWnd, WM_COMMAND, IDM_ROW_EDIT, 0);
}
+ if (pHdr->code == (DWORD)NM_CLICK && pHdr->hwndFrom == hListWnd) {
+ NMITEMACTIVATE* ia = (LPNMITEMACTIVATE) lParam;
+ return SendMessage(hWnd, WMU_SET_CURRENT_CELL, ia->iItem, ia->iSubItem);
+ }
+
+ if (isTable && pHdr->hwndFrom == hListWnd && pHdr->code == (UINT)NM_CUSTOMDRAW) {
+ NMLVCUSTOMDRAW* pCustomDraw = (LPNMLVCUSTOMDRAW)lParam;
+
+ int result = CDRF_DODEFAULT;
+ if (pCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT)
+ result = CDRF_NOTIFYITEMDRAW;
+
+ if (pCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
+ result = CDRF_NOTIFYSUBITEMDRAW | CDRF_NEWFONT;
+
+ if ((pCustomDraw->nmcd.dwDrawStage == CDDS_POSTPAINT) | CDDS_ITEM) {
+ if (pCustomDraw->nmcd.dwItemSpec == (DWORD)currCell.iItem) {
+ RECT rect;
+ ListView_GetSubItemRect(hListWnd, currCell.iItem, currCell.iSubItem, LVIR_BOUNDS, &rect);
+
+ HPEN hPen = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
+ HDC hdc = pCustomDraw->nmcd.hdc;
+ SelectObject(hdc, hPen);
+
+ RECT rc {0};
+ ListView_GetSubItemRect(hListWnd, currCell.iItem, currCell.iSubItem, LVIR_BOUNDS, &rc);
+ MoveToEx(hdc, rc.left - 2, rc.top, 0);
+ LineTo(hdc, rc.right - 1, rc.top);
+ LineTo(hdc, rc.right - 1, rc.bottom - 2);
+ LineTo(hdc, rc.left + 1, rc.bottom - 2);
+ LineTo(hdc, rc.left + 1, rc.top);
+ }
+ }
+
+ SetWindowLongPtr(hWnd, DWLP_MSGRESULT, result);
+ return true;
+ }
+
if (pHdr->code == LVN_KEYDOWN && pHdr->hwndFrom == hListWnd) {
NMLVKEYDOWN* kd = (LPNMLVKEYDOWN) lParam;
- if (kd->wVKey == 0x43 && GetKeyState(VK_CONTROL)) { // Ctrl + C
+
+ bool isControl = GetAsyncKeyState(VK_CONTROL);
+ if (kd->wVKey == VK_F5) {
+ PostMessage(hWnd, WM_COMMAND, IDM_ROW_REFRESH, 0);
+ return true;
+ }
+
+ if (kd->wVKey == 0x43 && isControl) { // Ctrl + C
currCell = {hListWnd, 0, 0};
PostMessage(hWnd, WM_COMMAND, IDM_RESULT_COPY_ROW, 0);
+ return true;
}
- if (kd->wVKey == 0x41 && GetKeyState(VK_CONTROL)) // Ctrl + A
+ if (kd->wVKey == 0x41 && isControl) { // Ctrl + A
ListView_SetItemState(hListWnd, -1, LVIS_SELECTED, LVIS_SELECTED);
+ return true;
+ }
- if (isTable && kd->wVKey == VK_DELETE)
+ if (kd->wVKey == 0x56 && isControl && currCell.iSubItem > 0) { // Ctrl + V
+ TCHAR* clipboard = utils::getClipboardText();
+ ListView_UpdateCell(hListWnd, currCell.iItem, currCell.iSubItem, clipboard);
+ delete [] clipboard;
+ return true;
+ }
+
+ if (isTable && kd->wVKey == VK_DELETE) {
PostMessage(hWnd, WM_COMMAND, IDM_ROW_DELETE, 0);
+ return true;
+ }
+
+ if (isTable && (kd->wVKey == VK_NEXT || kd->wVKey == VK_PRIOR || kd->wVKey == VK_HOME || kd->wVKey == VK_END)) {
+ PostMessage(hWnd, WMU_SYNC_CURRENT_CELL, 0, 0);
+ return true;
+ }
+
+ if (isTable && (kd->wVKey == VK_UP || kd->wVKey == VK_DOWN)) {
+ int rowCount = ListView_GetItemCount(hListWnd);
+ int rowNo = (currCell.iItem + rowCount + (kd->wVKey == VK_UP ? -1 : 1)) % rowCount;
+ SendMessage(hWnd, WMU_SET_CURRENT_CELL, rowNo, currCell.iSubItem);
+ ListView_SetItemState(hListWnd, -1, 0, LVIS_SELECTED);
+ ListView_SetItemState(hListWnd, rowNo, LVIS_SELECTED, LVIS_SELECTED);
+ SetWindowLongPtr(hWnd, DWLP_MSGRESULT, true);
+ return true;
+ }
+
+ if (isTable && (kd->wVKey == VK_LEFT || kd->wVKey == VK_RIGHT)) {
+ int colCount = Header_GetItemCount(ListView_GetHeader(hListWnd));
+ int colNo = (currCell.iSubItem + colCount + (kd->wVKey == VK_LEFT ? -1 : 1)) % colCount;
+ colNo = colNo == 0 && kd->wVKey == VK_LEFT ? colCount - 2 : colNo == colCount - 1 && kd->wVKey == VK_RIGHT ? 1 : colNo;
+ SendMessage(hWnd, WMU_SET_CURRENT_CELL, currCell.iItem, colNo);
+ SetWindowLongPtr(hWnd, DWLP_MSGRESULT, true);
+ return true;
+ }
+
bool isNum = kd->wVKey >= 0x31 && kd->wVKey <= 0x39;
bool isNumPad = kd->wVKey >= 0x61 && kd->wVKey <= 0x69;
- if ((isNum || isNumPad) && GetKeyState(VK_CONTROL)) // Ctrl + 1-9
- return ListView_Sort(pHdr->hwndFrom, kd->wVKey - (isNum ? 0x31 : 0x61) + 1 );
+ if ((isNum || isNumPad) && isControl) {// Ctrl + 1-9
+ ListView_Sort(pHdr->hwndFrom, kd->wVKey - (isNum ? 0x31 : 0x61) + 1);
+ if (isTable)
+ PostMessage(hWnd, WMU_SYNC_CURRENT_CELL, 0, 0);
+ return true;
+ }
+
+ if (isTable && !isControl && kd->wVKey >= 0x30 && kd->wVKey <= 0x5A) { // 0, 1, ..., y, z
+ SendMessage(hWnd, WMU_EDIT_VALUE, 0, kd->wVKey);
+ SetWindowLongPtr(hWnd, DWLP_MSGRESULT, true);
+ return true;
+ }
+
+ if (isTable && kd->wVKey == VK_INSERT)
+ SendMessage(hWnd, WM_COMMAND, IDM_ROW_ADD, 0);
}
if (isTable && pHdr->code == (DWORD)NM_DBLCLK && pHdr->hwndFrom == hListWnd) {
@@ -818,28 +1027,18 @@ namespace dialogs {
if (ia->iSubItem == 0 || ia->iSubItem == Header_GetItemCount(ListView_GetHeader(hListWnd)) - 1)
return true;
- RECT rect;
- ListView_GetSubItemRect(hListWnd, ia->iItem, ia->iSubItem, LVIR_BOUNDS, &rect);
- int h = rect.bottom - rect.top;
- int w = ListView_GetColumnWidth(hListWnd, ia->iSubItem);
-
- TCHAR buf[MAX_TEXT_LENGTH];
- ListView_GetItemText(hListWnd, ia->iItem, ia->iSubItem, buf, MAX_TEXT_LENGTH);
-
- if (_tcscmp(buf, TEXT("(BLOB)")) == 0)
- return 1;
+ currCell = {hListWnd, ia->iItem, ia->iSubItem};
+ }
- HWND hBtn = CreateWindowEx(0, WC_BUTTON, TEXT("..."), WS_CHILD | WS_VISIBLE | BS_FLAT, rect.left + w - 20, rect.top, 20, h, hListWnd, 0, GetModuleHandle(NULL), NULL);
- SendMessage(hBtn, WM_SETFONT, (LPARAM)hDefFont, true);
- SetWindowLong(hBtn, GWL_USERDATA, MAKELPARAM(ia->iItem, ia->iSubItem));
+ if (isTable && pHdr->code == (DWORD)NM_DBLCLK && pHdr->hwndFrom == hListWnd)
+ return SendMessage(hWnd, WMU_EDIT_VALUE, 1, 0);
- HWND hEdit = CreateWindowEx(0, WC_EDIT, buf, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, rect.left, rect.top, w - 20, h, hListWnd, 0, GetModuleHandle(NULL), NULL);
- SetWindowLong(hEdit, GWL_USERDATA, MAKELPARAM(ia->iItem, ia->iSubItem));
- int end = GetWindowTextLength(hEdit);
- SendMessage(hEdit, EM_SETSEL, end, end);
- SendMessage(hEdit, WM_SETFONT, (LPARAM)hDefFont, true);
- cbOldEditDataEdit = (WNDPROC)SetWindowLong(hEdit, GWL_WNDPROC, (LONG)cbNewEditDataEdit);
- SetFocus(hEdit);
+ // This event is triggered on ListView_SetData too. So ListView is hiding to prevent processing of the notification.
+ if (pHdr->code == HDN_ITEMCHANGED && pHdr->hwndFrom == ListView_GetHeader(hListWnd) && IsWindowVisible(hListWnd)) {
+ int* widths = (int*)GetProp(hWnd, TEXT("WIDTHS"));
+ int colNo = ((LPNMHEADER)lParam)->iItem;
+ widths[colNo] = ListView_GetColumnWidth(hListWnd, colNo);
+ SendMessage(hWnd, WMU_UPDATE_COLSIZE, 0, 0);
}
}
break;
@@ -853,7 +1052,7 @@ namespace dialogs {
if (wParam == IDOK) { // User push Enter
int pos = ListView_GetNextItem(hListWnd, -1, LVNI_SELECTED);
if (hListWnd == GetFocus() && pos != -1) {
- currCell = {hListWnd, pos, 0};
+ currCell = {hListWnd, pos, currCell.iSubItem};
PostMessage(hWnd, WM_COMMAND, IDM_ROW_EDIT, 0);
}
}
@@ -861,23 +1060,29 @@ namespace dialogs {
if (cmd == IDC_DLG_CANCEL || cmd == IDCANCEL)
SendMessage(hWnd, WM_CLOSE, 0, 0);
- if (cmd == IDM_RESULT_COPY_CELL || cmd == IDM_RESULT_COPY_ROW || cmd == IDM_RESULT_EXPORT)
+ if (cmd == IDM_RESULT_CHART || cmd == IDM_RESULT_COPY_CELL || cmd == IDM_RESULT_COPY_ROW || cmd == IDM_RESULT_EXPORT)
onListViewMenu(cmd, true);
- if (cmd == IDC_DLG_ROW_ADD)
+ if (cmd == IDM_ROW_ADD)
DialogBoxParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_ROW), hWnd, (DLGPROC)&cbDlgRow, MAKELPARAM(ROW_ADD, 0));
- if (cmd == IDC_DLG_ROW_DEL)
- SendMessage(hWnd, WM_COMMAND, MAKELPARAM(IDM_ROW_DELETE, 0), 0);
-
- if (cmd == IDC_DLG_REFRESH)
+ if (cmd == IDM_ROW_REFRESH)
SendMessage(hWnd, WMU_UPDATE_DATA, 0, 0);
- if (cmd == IDM_ROW_EDIT)
+ if (cmd == IDM_VALUE_EDIT) {
+ TCHAR buf[MAX_TEXT_LENGTH]{0};
+ ListView_GetItemText(hListWnd, currCell.iItem, currCell.iSubItem, buf, MAX_TEXT_LENGTH);
+
+ if (DLG_OK == DialogBoxParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_EDITDATA_VALUE), hWnd, (DLGPROC)&cbDlgEditDataValue, (LPARAM)buf))
+ ListView_UpdateCell(hListWnd, currCell.iItem, currCell.iSubItem, buf);
+ }
+
+ if (cmd == IDM_ROW_EDIT) {
DialogBoxParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_ROW), hWnd, (DLGPROC)&cbDlgRow, MAKELPARAM(isTable ? ROW_EDIT: ROW_VIEW, 0));
+ SendMessage(hWnd, WMU_SET_CURRENT_CELL, currCell.iItem, currCell.iSubItem);
+ }
if (cmd == IDM_ROW_DELETE) {
- HWND hListWnd = GetDlgItem(hWnd, IDC_DLG_QUERYLIST);
int count = ListView_GetSelectedCount(hListWnd);
if (!count)
return true;
@@ -907,8 +1112,6 @@ namespace dialogs {
delete [] buf8;
}
-
-
if (SQLITE_DONE == sqlite3_step(stmt)) {
pos = -1;
while((pos = ListView_GetNextItem(hListWnd, -1, LVNI_SELECTED)) != -1)
@@ -1047,6 +1250,9 @@ namespace dialogs {
delete [] path8;
}
+ if (cmd == IDM_GENERATE_DATA && (DLG_OK == DialogBoxParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_TOOL_GENERATE_DATA), hMainWnd, (DLGPROC)&tools::cbDlgDataGenerator, (LPARAM)editTableData16)))
+ SendMessage(hWnd, WMU_UPDATE_DATA, 0, 0);
+
if (HIWORD(wParam) == EN_CHANGE && (HWND)lParam == GetDlgItem(hWnd, IDC_DLG_QUERYFILTER) && (HWND)lParam == GetFocus()) {
KillTimer(hWnd, IDT_EDIT_DATA);
SetTimer(hWnd, IDT_EDIT_DATA, 300, NULL);
@@ -1054,34 +1260,6 @@ namespace dialogs {
}
break;
- case WM_PARENTNOTIFY: {
- if (LOWORD(wParam) == WM_LBUTTONDOWN) {
- POINT p = {LOWORD(lParam), HIWORD(lParam)};
- ClientToScreen(hWnd, &p);
-
- HWND hBtn = WindowFromPoint(p);
- TCHAR wndClass[256];
- GetClassName(hBtn, wndClass, 256);
- if (hBtn && !_tcscmp(wndClass, WC_BUTTON))
- PostMessage(hWnd, WMU_EDIT_VALUE, GetWindowLong(hBtn, GWL_USERDATA), 0);
- }
- }
- break;
-
- case WMU_EDIT_VALUE: {
- // DialogBoxParam raises beep value cause focus changed
- // To avoid beep use a post action
- LONG data = wParam;
- HWND hListWnd = GetDlgItem(hWnd, IDC_DLG_QUERYLIST);
-
- TCHAR buf[MAX_TEXT_LENGTH]{0};
- ListView_GetItemText(hListWnd, LOWORD(data), HIWORD(data), buf, MAX_TEXT_LENGTH);
-
- if (DLG_OK == DialogBoxParam(GetModuleHandle(0), MAKEINTRESOURCE(IDD_EDITDATA_VALUE), hWnd, (DLGPROC)&cbDlgEditDataValue, (LPARAM)buf))
- ListView_UpdateCell(hListWnd, LOWORD(data), HIWORD(data), buf);
- }
- break;
-
case WM_CLOSE: {
char* tablename8 = (char*)GetProp(hWnd, TEXT("TABLENAME8"));
delete [] tablename8;
@@ -1095,6 +1273,10 @@ namespace dialogs {
delete [] blobs;
RemoveProp(hWnd, TEXT("BLOBS"));
+ int* widths = (int*)GetProp(hWnd, TEXT("WIDTHS"));
+ delete [] widths;
+ RemoveProp(hWnd, TEXT("WIDTHS"));
+
RemoveProp(hWnd, TEXT("HASROWID"));
RemoveProp(hWnd, TEXT("KEYCOUNT"));
@@ -1645,7 +1827,7 @@ namespace dialogs {
#define CHART_BORDER 40
#define CHART_GRID 5
- #define CHART_BARS_LEFT 150
+ #define CHART_BARS_LEFT 180
#define CHART_BAR_HEIGHT 20
#define CHART_BAR_SPACE 3
@@ -1985,12 +2167,13 @@ namespace dialogs {
TextOut(hdc, x, y, name16, _tcslen(name16));
lineNo++;
}
+ }
- if (lineNo == 0 && type != CHART_NONE) {
- SetProp(hWnd, TEXT("TYPE"), (HANDLE)CHART_NONE);
- PostMessage(hWnd, WM_PAINT, 0, 0);
- }
+ if (lineNo == 0) {
+ SetProp(hWnd, TEXT("TYPE"), (HANDLE)CHART_NONE);
+ PostMessage(hWnd, WM_PAINT, 0, 0);
}
+
DeleteObject(hPen);
}
@@ -2044,6 +2227,92 @@ namespace dialogs {
return false;
}
+ // lParam and USERDATA are sqlite3 statement handle
+ BOOL CALLBACK cbDlgBindParameters (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ switch (msg) {
+ case WM_INITDIALOG: {
+ SetWindowLong(hWnd, GWL_USERDATA, (LONG)lParam);
+
+ sqlite3_stmt* stmt = (sqlite3_stmt*)lParam;
+ sqlite3_stmt* stmt2;
+ sqlite3_prepare_v2(db, "select value from preferences.query_params where lower(dbname) = lower(?1) and lower(name) = lower(?2)", -1, &stmt2, 0);
+ char* dbname8 = utils::getFileName(sqlite3_db_filename(db, 0));
+
+ int paramCount = sqlite3_bind_parameter_count(stmt);
+ for (int i = 1; i < paramCount + 1; i++) {
+ const char* name8 = (char*)sqlite3_bind_parameter_name(stmt, i);
+ TCHAR* name16 = utils::utf8to16(name8);
+ if (_tcslen(name16)) {
+ CreateWindow(WC_STATIC, name16, WS_VISIBLE | WS_CHILD | SS_RIGHT, 5, 10 + 30 * (i - 1), 100, 18, hWnd, (HMENU)(IDC_ROW_LABEL + i), GetModuleHandle(0), 0);
+ HWND hComboWnd = CreateWindow(WC_COMBOBOX, NULL, WS_VISIBLE | WS_CHILD | WS_BORDER | WS_CLIPSIBLINGS | WS_TABSTOP | CBS_DROPDOWN, 110, 7 + 30 * (i - 1), 184, 200, hWnd, (HMENU)(IDC_ROW_EDIT + i), GetModuleHandle(0), 0);
+
+ sqlite3_reset(stmt2);
+ sqlite3_bind_text(stmt2, 1, dbname8, strlen(dbname8), SQLITE_TRANSIENT);
+ sqlite3_bind_text(stmt2, 2, name8, strlen(name8), SQLITE_TRANSIENT);
+
+ while(SQLITE_ROW == sqlite3_step(stmt2)) {
+ TCHAR* value16 = utils::utf8to16((char*)sqlite3_column_text(stmt2, 0));
+ ComboBox_AddString(hComboWnd, value16);
+ delete [] value16;
+ }
+ } else {
+ CreateWindow(WC_STATIC, TEXT("(Unnamed)"), WS_VISIBLE | WS_CHILD | SS_RIGHT, 5, 10 + 30 * (i - 1), 100, 18, hWnd, (HMENU)(IDC_ROW_LABEL + i), GetModuleHandle(0), 0);
+ CreateWindow(WC_EDIT, NULL, WS_VISIBLE | WS_CHILD | WS_BORDER | WS_CLIPSIBLINGS | WS_TABSTOP | CBS_DROPDOWN, 110, 7 + 30 * (i - 1), 184, 20, hWnd, (HMENU)(IDC_ROW_EDIT + i), GetModuleHandle(0), 0);
+ }
+ delete [] name16;
+ }
+ sqlite3_finalize(stmt2);
+ EnumChildWindows(hWnd, (WNDENUMPROC)cbEnumChildren, (LPARAM)ACTION_SETDEFFONT);
+
+ SetWindowPos(hWnd, 0, 0, 0, 305, paramCount * 30 + 62, SWP_NOMOVE | SWP_NOZORDER);
+ SetWindowPos(GetDlgItem(hWnd, IDC_DLG_OK), 0, 204, paramCount * 30 + 8, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+ delete [] dbname8;
+
+ SetFocus(GetDlgItem(hWnd, IDC_ROW_EDIT + 1));
+ }
+ break;
+
+ case WM_COMMAND: {
+ if (wParam == IDC_DLG_OK) {
+ sqlite3_stmt* stmt = (sqlite3_stmt*)GetWindowLong(hWnd, GWL_USERDATA);;
+ sqlite3_stmt* stmt2;
+ sqlite3_prepare_v2(db, "replace into preferences.query_params (dbname, name, value) values (?1, ?2, ?3);", -1, &stmt2, 0);
+ char* dbname8 = utils::getFileName(sqlite3_db_filename(db, 0));
+
+ int paramCount = sqlite3_bind_parameter_count(stmt);
+ for (int i = 1; i <= paramCount; i++) {
+ TCHAR name16[1024];
+ GetDlgItemText(hWnd, IDC_ROW_LABEL + i, name16, 1023);
+ char* name8 = utils::utf16to8(name16);
+
+ TCHAR value16[1024];
+ GetDlgItemText(hWnd, IDC_ROW_EDIT + i, value16, 1023);
+ char* value8 = utils::utf16to8(value16);
+ utils::sqlite3_bind_variant(stmt, i, value8);
+
+ sqlite3_reset(stmt2);
+ sqlite3_bind_text(stmt2, 1, dbname8, strlen(dbname8), SQLITE_TRANSIENT);
+ sqlite3_bind_text(stmt2, 2, name8, strlen(name8), SQLITE_TRANSIENT);
+ sqlite3_bind_text(stmt2, 3, value8, strlen(value8), SQLITE_TRANSIENT);
+ sqlite3_step(stmt2);
+
+ delete [] name8;
+ delete [] value8;
+ }
+ sqlite3_finalize(stmt2);
+
+ EndDialog(hWnd, DLG_OK);
+ }
+
+ if (wParam == IDC_DLG_CANCEL || wParam == IDCANCEL)
+ EndDialog(hWnd, DLG_CANCEL);
+ }
+ break;
+ }
+
+ return false;
+ }
+
BOOL CALLBACK cbEnumFont(LPLOGFONT lplf, LPNEWTEXTMETRIC lpntm, DWORD fontType, LPVOID hWnd) {
if (fontType & TRUETYPE_FONTTYPE && lplf->lfFaceName[0] != TEXT('@'))
ComboBox_AddString((HWND)hWnd, lplf->lfFaceName);
@@ -2177,15 +2446,16 @@ namespace dialogs {
DestroyWindow(hBtn);
int data = GetWindowLong(hWnd, GWL_USERDATA);
- if (!data) // Exit by Esc
- return 0;
-
- int size = GetWindowTextLength(hWnd);
- TCHAR value16[size + 1]{0};
- GetWindowText(hWnd, value16, size + 1);
- ListView_UpdateCell(hListWnd, LOWORD(data), HIWORD(data), value16);
+ if (data) {
+ int size = GetWindowTextLength(hWnd);
+ TCHAR value16[size + 1]{0};
+ GetWindowText(hWnd, value16, size + 1);
+ ListView_UpdateCell(hListWnd, LOWORD(data), HIWORD(data), value16);
+ }
+ SetFocus(hListWnd);
}
break;
+
case WM_KILLFOCUS: {
DestroyWindow(hWnd);
}
@@ -2193,10 +2463,6 @@ namespace dialogs {
case WM_KEYDOWN: {
if (wParam == VK_RETURN) {
- int style = GetWindowLong(hWnd, GWL_STYLE);
- if((style & ES_MULTILINE) == ES_MULTILINE && GetAsyncKeyState(VK_CONTROL))
- break;
-
DestroyWindow(hWnd);
}
@@ -2254,6 +2520,29 @@ namespace dialogs {
return CallWindowProc(cbOldAddTableCell, hWnd, msg, wParam, lParam);
}
+ LRESULT CALLBACK cbNewFilterEdit(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ if (msg == WM_GETDLGCODE)
+ return (DLGC_WANTALLKEYS | CallWindowProc(cbOldHeaderEdit, hWnd, msg, wParam, lParam));
+
+ switch(msg){
+ case WM_CHAR:
+ case WM_KEYDOWN: {
+ if (wParam == VK_RETURN || wParam == VK_ESCAPE) {
+ HWND hDlg = GetParent(GetParent(hWnd));
+ if (msg == WM_KEYDOWN) {
+ SendMessage(hDlg, wParam == VK_RETURN ? WMU_UPDATE_DATA : WM_CLOSE, 0, 0);
+ SendMessage(GetParent(hDlg), wParam == VK_RETURN ? WMU_UPDATE_DATA : WM_CLOSE, 0, 0);
+ }
+ return 0;
+ }
+ }
+ break;
+ }
+
+ return CallWindowProc(cbOldHeaderEdit, hWnd, msg, wParam, lParam);
+ }
+
+
bool ListView_UpdateCell(HWND hListWnd, int rowNo, int colNo, TCHAR* value16) {
HWND hHeader = (HWND)ListView_GetHeader(hListWnd);
TCHAR column16[256]{0};
diff --git a/src/dialogs.h b/src/dialogs.h
index 973ec85..9838f7d 100644
--- a/src/dialogs.h
+++ b/src/dialogs.h
@@ -16,6 +16,7 @@ namespace dialogs {
BOOL CALLBACK cbDlgFind (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK cbDlgDDL (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK cbDlgChart (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+ BOOL CALLBACK cbDlgBindParameters (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
}
#endif
diff --git a/src/global.h b/src/global.h
index 87232a7..b1ffc74 100644
--- a/src/global.h
+++ b/src/global.h
@@ -44,6 +44,7 @@
#include
#include
+#include "missing.h"
#include "sqlite3.h"
extern sqlite3 *db;
@@ -59,8 +60,8 @@ extern const TCHAR *TYPES16u[5];
extern const TCHAR *TYPES16p[5];
extern HFONT hDefFont;
-extern WNDPROC cbOldResultList;
-LRESULT CALLBACK cbNewResultList(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+extern WNDPROC cbOldListView;
+LRESULT CALLBACK cbNewListView(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
bool CALLBACK cbEnumChildren (HWND hWnd, LPARAM action);
int CALLBACK cbListComparator(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
diff --git a/src/main.cpp b/src/main.cpp
index 9b0c8b8..2d710b1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -81,12 +81,12 @@ int enableDbObject(const char* name8, int type);
int disableDbObject(const char* name8, int type);
bool isQueryValid(const char* query);
-WNDPROC cbOldMainTab, cbOldMainTabRenameEdit, cbOldTreeItemEdit, cbOldAutoComplete, cbOldResultList;
+WNDPROC cbOldMainTab, cbOldMainTabRenameEdit, cbOldTreeItemEdit, cbOldAutoComplete, cbOldListView;
LRESULT CALLBACK cbNewTreeItemEdit(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK cbNewMainTab(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK cbNewMainTabRename(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK cbNewAutoComplete(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
-LRESULT CALLBACK cbNewResultList(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK cbNewListView(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK cbMainWindow (HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
@@ -168,7 +168,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
TCHAR* version16 = utils::utf8to16(version8);
SendMessage(hStatusWnd, SB_SETTEXT, 0, (LPARAM)version16);
delete [] version16;
- SendMessage(hStatusWnd, SB_SETTEXT, 1, (LPARAM)TEXT(" GUI: 1.3.7"));
+ SendMessage(hStatusWnd, SB_SETTEXT, 1, (LPARAM)TEXT(" GUI: 1.3.8"));
hTreeWnd = CreateWindowEx(0, WC_TREEVIEW, NULL, WS_VISIBLE | WS_CHILD | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | WS_DISABLED | TVS_EDITLABELS, 0, 0, 100, 100, hMainWnd, (HMENU)IDC_TREE, hInstance, NULL);
hMainTabWnd = CreateWindowEx(0, WC_STATIC, NULL, WS_VISIBLE | WS_CHILD | SS_NOTIFY, 100, 0, 100, 100, hMainWnd, (HMENU)IDC_MAINTAB, hInstance, NULL);
@@ -294,6 +294,7 @@ LRESULT CALLBACK cbMainWindow (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam
switch (msg) {
case WM_DESTROY: {
sqlite3_close(db);
+ prefs::setSyncMode(0);
if (prefs::get("restore-editor")) {
int tabCurrent = SendMessage(hMainTabWnd, WMU_TAB_GET_CURRENT, 0, 0);
@@ -332,6 +333,8 @@ LRESULT CALLBACK cbMainWindow (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam
if (!prefs::save())
MessageBox(0, TEXT("Settings saving failed"), TEXT("Error"), MB_OK);
+ prefs::setSyncMode(1);
+
PostQuitMessage (0);
}
break;
@@ -475,9 +478,9 @@ LRESULT CALLBACK cbMainWindow (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam
SendMessage(hMainWnd, WM_CLOSE, 0, 0);
if (cmd == IDM_OPEN) {
- TCHAR path[MAX_PATH]{0};
- if (utils::openFile(path, TEXT("Databases (*.sqlite, *.sqlite3, *.db)\0*.sqlite;.sqlite3;.id\0All\0*.*\0")))
- openDb(path);
+ TCHAR path16[MAX_PATH]{0};
+ if (utils::openFile(path16, TEXT("Databases (*.sqlite, *.sqlite3, *.db)\0*.sqlite;*.sqlite3;*.db\0All\0*.*\0")))
+ openDb(path16);
}
if (cmd == IDM_CLOSE)
@@ -485,12 +488,12 @@ LRESULT CALLBACK cbMainWindow (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam
if (cmd == IDM_ATTACH) {
TCHAR path16[MAX_PATH]{0};
- if (utils::openFile(path16, TEXT("*.sqlite\0*.sqlite\0*.db\0*.db\0All\0*.*\0"))) {
- TCHAR name16[256]{0};
+ if (utils::openFile(path16, TEXT("Databases (*.sqlite, *.sqlite3, *.db)\0*.sqlite;*.sqlite3;*.db\0All\0*.*\0"))) {
+ TCHAR name16[MAX_PATH]{0};
_tsplitpath(path16, NULL, NULL, name16, NULL);
for(int i = 0; name16[i]; i++)
name16[i] = _totlower(name16[i]);
- TCHAR query16[256]{0};
+ TCHAR query16[2 * _tcslen(path16) + 255]{0};
_stprintf(query16, TEXT("attach database \"%s\" as \"%s\""), path16, name16);
executeCommandQuery(query16);
}
@@ -1128,18 +1131,18 @@ LRESULT CALLBACK cbMainWindow (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam
}
if (pHdr->hwndFrom == hTreeWnd && pHdr->code == (UINT)NM_CUSTOMDRAW) {
- LPNMTVCUSTOMDRAW pCustomDraw = (LPNMTVCUSTOMDRAW)lParam;
- if (pCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT)
- return CDRF_NOTIFYITEMDRAW;
-
- if (pCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) {
- BOOL isCut = TreeView_GetItemState(pHdr->hwndFrom, (HTREEITEM)pCustomDraw->nmcd.dwItemSpec, TVIS_CUT) & TVIS_CUT;
- pCustomDraw->clrText = pCustomDraw->clrTextBk != RGB(255, 255, 255) ? RGB(255, 255, 255) :
- isCut ? RGB(200, 200, 200) : RGB(0, 0, 0);
- }
+ LPNMTVCUSTOMDRAW pCustomDraw = (LPNMTVCUSTOMDRAW)lParam;
+ if (pCustomDraw->nmcd.dwDrawStage == CDDS_PREPAINT)
+ return CDRF_NOTIFYITEMDRAW;
+
+ if (pCustomDraw->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) {
+ BOOL isCut = TreeView_GetItemState(pHdr->hwndFrom, (HTREEITEM)pCustomDraw->nmcd.dwItemSpec, TVIS_CUT) & TVIS_CUT;
+ pCustomDraw->clrText = pCustomDraw->clrTextBk != RGB(255, 255, 255) ? RGB(255, 255, 255) :
+ isCut ? RGB(200, 200, 200) : RGB(0, 0, 0);
+ }
- return CDRF_DODEFAULT;
- }
+ return CDRF_DODEFAULT;
+ }
if (pHdr->code == TTN_GETDISPINFO) {
LPTOOLTIPTEXT pTtt = (LPTOOLTIPTEXT) lParam;
@@ -1309,14 +1312,22 @@ LRESULT CALLBACK cbMainWindow (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam
return 0;
}
-LRESULT CALLBACK cbNewResultList(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+LRESULT CALLBACK cbNewListView(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ // Quick reference tooltip
if (msg == WM_SYSKEYDOWN && wParam == VK_MENU)
return 1;
if (msg == WM_SYSKEYUP && wParam == VK_MENU && IsWindowVisible(hTooltipWnd))
SendMessage(hTooltipWnd, TTM_TRACKACTIVATE, false, 0);
- return CallWindowProc(cbOldResultList, hWnd, msg, wParam, lParam);
+ // Prevent zero-width column resizing
+ if(msg == WM_NOTIFY) {
+ NMHDR* pHdr = (LPNMHDR)lParam;
+ if ((pHdr->code == HDN_BEGINTRACK || pHdr->code == HDN_DIVIDERDBLCLICK) && ListView_GetColumnWidth(hWnd, ((LPNMHEADER)lParam)->iItem) == 0)
+ return true;
+ }
+
+ return CallWindowProc(cbOldListView, hWnd, msg, wParam, lParam);
}
LRESULT CALLBACK cbNewTreeItemEdit(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
@@ -1362,7 +1373,17 @@ int executeCLIQuery(bool isPlan) {
rc = sqlite3_prepare_v2(db, sql8, -1, &stmt, 0);
}
+ if (sqlite3_bind_parameter_count(stmt))
+ DialogBoxParam (GetModuleHandle(0), MAKEINTRESOURCE(IDD_BIND_PARAMETERS), hMainWnd, (DLGPROC)&dialogs::cbDlgBindParameters, (LPARAM)stmt);
+
TCHAR result16[MAX_TEXT_LENGTH]{0};
+ if (sqlite3_bind_parameter_count(stmt)) {
+ _tcscat(result16, TEXT("EXECUTE: "));
+ TCHAR* esql16 = utils::utf8to16(sqlite3_expanded_sql(stmt));
+ _tcscat(result16, esql16);
+ _tcscat(result16, TEXT("\n"));
+ delete [] esql16;
+ }
if (rc == SQLITE_OK) {
DWORD tStart = GetTickCount();
@@ -1623,11 +1644,13 @@ int executeQuery(TCHAR* query, int tabId, bool isPlan) {
}
int colCount = rc == SQLITE_OK ? sqlite3_column_count(stmt) : 0;
+ if (sqlite3_bind_parameter_count(stmt))
+ DialogBoxParam (GetModuleHandle(0), MAKEINTRESOURCE(IDD_BIND_PARAMETERS), hMainWnd, (DLGPROC)&dialogs::cbDlgBindParameters, (LPARAM)stmt);
+
HWND hResultWnd = 0;
int rowCount = 0;
if (rc == SQLITE_OK && colCount > 0) {
hResultWnd = CreateWindow(WC_LISTVIEW, NULL, WS_TABSTOP | WS_CHILD | LVS_AUTOARRANGE | LVS_REPORT | LVS_SHOWSELALWAYS, 20, 20, 100, 100, tab->hTabWnd, (HMENU)0, GetModuleHandle(0), NULL);
- cbOldResultList = (WNDPROC)SetWindowLong(hResultWnd, GWL_WNDPROC, (LONG)cbNewResultList);
rowCount = ListView_SetData(hResultWnd, stmt, true);
rc = sqlite3_errcode(db);
if (rc != SQLITE_OK && rowCount == 0) {
@@ -2566,6 +2589,9 @@ int ListView_SetData(HWND hListWnd, sqlite3_stmt *stmt, bool isRef) {
ListView_SetColumnWidth(hListWnd, i, 60);
}
+ if ((WNDPROC)GetWindowLong(hListWnd, GWL_WNDPROC) != cbNewListView)
+ cbOldListView = (WNDPROC)SetWindowLong(hListWnd, GWL_WNDPROC, (LONG)cbNewListView);
+
return isStopByLimit ? -rowNo : rowNo;
}
diff --git a/src/missing.h b/src/missing.h
index 0484663..18f6370 100644
--- a/src/missing.h
+++ b/src/missing.h
@@ -11,4 +11,14 @@ typedef struct tagTVKEYDOWN {
#define LVS_EX_AUTOSIZECOLUMNS 0x10000000
#define CFM_BACKCOLOR 0x04000000
+#define HDN_FILTERCHANGE (HDN_FIRST-12)
+#define HDN_FILTERBTNCLICK (HDN_FIRST-13)
+#define HDN_BEGINFILTEREDIT (HDN_FIRST-14)
+#define HDN_ENDFILTEREDIT (HDN_FIRST-15)
+
+#define HDM_SETFILTERCHANGETIMEOUT (HDM_FIRST + 22)
+#define HDM_CLEARFILTER (HDM_FIRST + 24)
+#define LVN_INCREMENTALSEARCH (LVN_FIRST-63)
+
+
#endif
diff --git a/src/prefs.cpp b/src/prefs.cpp
index c7f2f0d..9c5477f 100644
--- a/src/prefs.cpp
+++ b/src/prefs.cpp
@@ -22,7 +22,7 @@ namespace prefs {
100, 100, 800, 600, 200, 200,
0, 10, 1000, 1, 0,
8, 10, 20,
- 1, 1, 1, 1, 1, 0, 0, 1, 0, 0,
+ 0, 1, 1, 1, 1, 0, 0, 1, 0, 0,
0, 0,
0, 0, 1,
10000,
@@ -38,10 +38,15 @@ namespace prefs {
return 0;
}
- void set(const char* name, int value) {
+ bool set(const char* name, int value) {
+ bool res = false;
for (int i = 0; i < ICOUNT; i++)
- if (!strcmp(iprops[i], name))
+ if (!strcmp(iprops[i], name)) {
ivalues[i] = value;
+ res = true;
+ }
+
+ return res;
}
char* get(const char* name, const char* def) {
@@ -58,7 +63,7 @@ namespace prefs {
return value;
}
- bool set(const char* name, char* value) {
+ bool set(const char* name, const char* value) {
sqlite3_stmt* stmt;
if (SQLITE_OK != sqlite3_prepare(db, "replace into 'prefs' (name, value) values (?1, ?2);", -1, &stmt, 0))
return false;
@@ -87,9 +92,9 @@ namespace prefs {
"create table if not exists disabled (dbpath text not null, type text not null, name text not null, sql text, primary key (dbpath, type, name)); " \
"create table if not exists cli (\"time\" real, dbname text not null, query text not null, elapsed integer, result text); " \
"create table if not exists diagrams (dbname text, tblname text, x integer, y integer, width integer, height integer, primary key (dbname, tblname));" \
+ "create table if not exists query_params (dbname text, name text, value text, primary key (dbname, name, value));" \
"create index if not exists idx_cli on cli (\"time\" desc, dbname);" \
- "commit;" \
- "pragma synchronous = 0;";
+ "commit;";
if (SQLITE_OK != sqlite3_exec(db, sql8, 0, 0, 0))
return false;
@@ -257,6 +262,7 @@ namespace prefs {
return rc == SQLITE_DONE || rc == SQLITE_OK;
}
+
bool setDiagramRect(const char* dbname, const char* table, RECT rect) {
sqlite3_stmt* stmt;
int rc = sqlite3_prepare(db, "replace into 'diagrams' (dbname, tblname, x, y, width, height) values (?1, ?2, ?3, ?4, ?5, ?6)", -1, &stmt, 0);
@@ -274,4 +280,10 @@ namespace prefs {
return rc == SQLITE_DONE || rc == SQLITE_OK;
}
+
+ bool setSyncMode(int mode) {
+ char query[255];
+ sprintf(query, "pragma synchronous = %i;", mode);
+ return SQLITE_DONE == sqlite3_exec(db, query, 0, 0, 0);
+ }
}
diff --git a/src/prefs.h b/src/prefs.h
index b4965c3..5d7f8f0 100644
--- a/src/prefs.h
+++ b/src/prefs.h
@@ -11,10 +11,10 @@ namespace prefs {
bool backup();
int get(const char* name);
- void set(const char* name, int value);
+ bool set(const char* name, int value);
char* get(const char* name, const char* def);
- bool set(const char* name, char* value);
+ bool set(const char* name, const char* value);
bool setRecent(char* path);
int getRecents(char** recents);
@@ -25,6 +25,8 @@ namespace prefs {
bool getDiagramRect(const char* dbname, const char* table, RECT* rect);
bool setDiagramRect(const char* dbname, const char* table, RECT rect);
+
+ bool setSyncMode(int mode);
}
#endif
diff --git a/src/resource.h b/src/resource.h
index 5443c5a..c289a1b 100644
--- a/src/resource.h
+++ b/src/resource.h
@@ -10,6 +10,7 @@
#define IDD_CHART 20
#define IDD_EDITDATA_VALUE 21
#define IDD_VIEWDATA_VALUE 22
+#define IDD_BIND_PARAMETERS 23
#define IDD_TOOL_EXPORT_CSV 30
#define IDD_TOOL_EXPORT_SQL 31
@@ -115,6 +116,8 @@
#define IDC_DLG_SEARCH_RESULT 193
#define IDC_DLG_SEARCH_ROWS 194
#define IDC_DLG_STATISTICS 195
+#define IDC_DLG_FILTER 196
+#define IDM_LAST_SEPARATOR 197
#define IDC_DLG_GEN_ISTRUNCATE 260
#define IDC_DLG_GEN_ROW_COUNT 261
@@ -134,6 +137,9 @@
#define IDC_TAB_EDIT 300
+#define IDC_HEADER_EDIT 400 // Iteratable
+#define IDC_HEADER_STATIC 450 // Iteratable
+
#define IDC_MENU_MAIN 500
#define IDC_MENU_EDITOR 501
#define IDC_MENU_RESULT 502
@@ -215,7 +221,6 @@
#define IDM_EDITOR_DELETE 1604
#define IDM_EDITOR_FIND 1605
-
#define IDM_RESULT_CHART 1610
#define IDM_RESULT_COPY_CELL 1611
#define IDM_RESULT_COPY_ROW 1612
@@ -247,9 +252,12 @@
#define IDM_ENABLE_ALL 1717
#define IDM_DISABLE_ALL 1718
-#define IDM_ROW_EDIT 1722
-#define IDM_ROW_DELETE 1723
-#define IDM_ROW_DUPLICATE 1724
+#define IDM_VALUE_EDIT 1721
+#define IDM_ROW_ADD 1722
+#define IDM_ROW_EDIT 1723
+#define IDM_ROW_DELETE 1724
+#define IDM_ROW_REFRESH 1725
+#define IDM_ROW_DUPLICATE 1726
#define IDM_LINK_FK 1731
#define IDM_LINK_VIEW 1732
@@ -258,10 +266,8 @@
#define IDI_LOGO 3000
#define IDB_TREEVIEW 3001
#define IDB_TOOLBAR 3002
-#define IDB_BTN_ADD 3003
-#define IDB_BTN_DELETE 3004
-#define IDB_BTN_REFRESH 3005
#define IDB_DIAGRAM_TOOLBAR 3006
+#define IDB_TOOLBAR_DATA 3010
#define IDS_CREATE_DDL 10000
#define IDS_CREATE_TABLE 10001
@@ -296,6 +302,9 @@
#define WMU_SHOW_TABLE_INFO WM_USER + 10
#define WMU_RESET_LISTVIEW WM_USER + 11
#define WMU_EDIT_VALUE WM_USER + 12
+#define WMU_UPDATE_COLSIZE WM_USER + 13
+#define WMU_SET_CURRENT_CELL WM_USER + 14
+#define WMU_SYNC_CURRENT_CELL WM_USER + 15
#define WMU_TAB_ADD WM_USER + 30
#define WMU_TAB_DELETE WM_USER + 31
@@ -305,7 +314,6 @@
#define WMU_TAB_GET_COUNT WM_USER + 36
#define WMU_TAB_GET_CURRENT WM_USER + 37
-
#define NM_TAB_ADD WM_USER + 40
#define NM_TAB_DELETE WM_USER + 41
#define NM_TAB_REQUEST_DELETE WM_USER + 42
diff --git a/src/resource.rc b/src/resource.rc
index be304df..53b7bbe 100644
--- a/src/resource.rc
+++ b/src/resource.rc
@@ -4,15 +4,15 @@
#include "resource.h"
1 VERSIONINFO
-FILEVERSION 1, 3, 7, 0
+FILEVERSION 1, 3, 8, 0
FILEOS VOS_DOS_WINDOWS32
FILETYPE VFT_APP {
BLOCK "StringFileInfo" {
BLOCK "040904E4" {
VALUE "FileDescription", "SQLite GUI\000"
- VALUE "FileVersion", "1.3.7\000"
+ VALUE "FileVersion", "1.3.8\000"
VALUE "ProductName", "sqlite-gui\000"
- VALUE "ProductVersion", "1.3.7\000"
+ VALUE "ProductVersion", "1.3.8\000"
VALUE "LegalCopyright", "Copyright \251 Little Brother 2020-2021\000"
VALUE "OriginalFilename", "sqlite-gui.exe\000"
}
@@ -101,10 +101,6 @@ IDD_EDITDATA DIALOGEX 50, 50, 500, 300
CAPTION "View/Edit table data"
FONT 10, "MS Shell Dlg", 400, 0, 0x1
BEGIN
- CONTROL "", IDC_DLG_ROW_ADD, WC_STATIC, SS_LEFT | SS_BITMAP | SS_CENTERIMAGE | SS_NOTIFY, 0, 0, 10, 10, 0
- CONTROL "", IDC_DLG_ROW_DEL, WC_STATIC, SS_LEFT | SS_BITMAP | SS_CENTERIMAGE | SS_NOTIFY, 11, 0, 10, 10, 0
- EDITTEXT IDC_DLG_QUERYFILTER, 22, 0, 300, 10, WS_BORDER | WS_TABSTOP, 0
- CONTROL "", IDC_DLG_REFRESH, WC_STATIC, SS_LEFT | SS_BITMAP | SS_CENTERIMAGE | SS_NOTIFY, 300, 0, 10, 10, 0
CONTROL "", IDC_DLG_QUERYLIST, WC_LISTVIEW, WS_VSCROLL | WS_TABSTOP | LVS_REPORT, 0, 10, 400, 80, WS_EX_STATICEDGE
END
@@ -325,7 +321,7 @@ IDD_TOOL_GENERATE_DATA DIALOGEX 50, 50, 250, 300
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Target", IDC_DLG_LABEL, 5, 7, 30, 14, SS_LEFT
- COMBOBOX IDC_DLG_TABLENAME, 30, 5, 120, 100, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST | CBS_SORT
+ COMBOBOX IDC_DLG_TABLENAME, 30, 5, 120, 100, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST
LTEXT "Row count", IDC_DLG_LABEL, 165, 7, 40, 14, SS_LEFT
EDITTEXT IDC_DLG_GEN_ROW_COUNT, 205, 5, 40, 12, WS_BORDER | WS_TABSTOP | ES_NUMBER | ES_CENTER
AUTOCHECKBOX "Truncate data before generation", IDC_DLG_GEN_ISTRUNCATE, 5, 20, 140, 16, BS_NOTIFY
@@ -366,6 +362,15 @@ IDD_CHART DIALOGEX 40, 30, 420, 260
BEGIN
END
+LANGUAGE 0, SUBLANG_NEUTRAL
+IDD_BIND_PARAMETERS DIALOGEX 40, 30, 200, 260
+ STYLE WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | DS_MODALFRAME
+ CAPTION "Binding values"
+ FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ PUSHBUTTON "OK", IDC_DLG_OK, 0, 0, 60, 14, WS_TABSTOP
+END
+
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDC_MENU_MAIN MENU
BEGIN
@@ -401,12 +406,12 @@ BEGIN
MENUITEM "Database search", IDM_DATABASE_SEARCH, GRAYED
MENUITEM "Workflow manager", IDM_WORKFLOW_MANAGER, GRAYED
MENUITEM SEPARATOR
- MENUITEM "Execute SQL file", IDM_IMPORT_SQL, GRAYED
- MENUITEM "Import from CSV file", IDM_IMPORT_CSV, GRAYED
+ MENUITEM "Import SQL file", IDM_IMPORT_SQL, GRAYED
+ MENUITEM "Import CSV file", IDM_IMPORT_CSV, GRAYED
MENUITEM "Import via ODBC", IDM_IMPORT_ODBC, GRAYED
MENUITEM "Export to SQL file", IDM_EXPORT_SQL, GRAYED
MENUITEM "Export as CSV file", IDM_EXPORT_CSV, GRAYED
- MENUITEM "Data generator", IDM_GENERATE_DATA, GRAYED
+ MENUITEM "Generate data", IDM_GENERATE_DATA, GRAYED
MENUITEM SEPARATOR
MENUITEM "Integrity check", IDM_CHECK_INTEGRITY, GRAYED
MENUITEM "Vacuum database", IDM_VACUUM, GRAYED
@@ -571,6 +576,8 @@ IDC_MENU_EDIT_DATA MENU
BEGIN
POPUP "Edit data"
BEGIN
+ MENUITEM "Edit value", IDM_VALUE_EDIT
+ MENUITEM SEPARATOR
MENUITEM "Edit\tEnter", IDM_ROW_EDIT
MENUITEM "Delete\tDel", IDM_ROW_DELETE
MENUITEM "Duplicate", IDM_ROW_DUPLICATE
@@ -676,8 +683,12 @@ BEGIN
"* Do you need a newer version of sqlite?\n Just replace sqlite3.dll! 32-bit version is required.\n\n" \
"* Data generator requires ora extension.\n\n" \
"* Disabled indexes and triggers are stored in ""preferences.disabled"" table.\n\n" \
- "Cons\n* Only utf-8 is supported\n* NULL is displayed as an empty string\n* An empty string is set to NULL when data is edit\n* Data diagram isn't accurate with building references in views/triggers\n"
- IDS_EXTENSIONS "Json1\n" \
+ "Cons\n" \
+ "* Only utf-8 is supported\n* NULL is displayed as an empty string\n" \
+ "* An empty string is set to NULL when data is edit\n" \
+ "* Data diagram isn't accurate with building references in views/triggers\n" \
+ "* The app is a single threaded, so the interface freeze on long operations \n"
+ IDS_EXTENSIONS L"Json1\n" \
"Various SQL functions and table-valued functions for processing JSON.\n\n" \
"Math\n" \
"This library provides common mathematical and string functions: acos, asin, atan, atn2, atan2, acosh, asinh, atanh, difference, degrees, radians, cos, sin, tan, cot, cosh, sinh, tanh, coth, exp, log, log10, power, sign, sqrt, square, ceil, floor, pi, replicate, charindex, leftstr, rightstr, ltrim, rtrim, trim, replace, reverse, proper, padl, padr, padc, strfilter, stdev, variance, mode, median, lower_quartile, upper_quartile.\n\n" \
@@ -689,9 +700,9 @@ BEGIN
"Regexp\n"\
"Implements regexp(regexp, stringToMatch) function and ""B regexp A"" operator. This is a non-POSIX regexp.\n\n" \
"Ora\n"\
- "Adds rownum(start), concat(str1, str2, ...), decode(expr, key1, value1, key2, value2, ..., defValue), crc32(str) and md5(str) functions.\n\n" \
+ "Adds rownum(start), concat(str1, str2, ...), decode(expr, key1, value1, key2, value2, ..., defValue), strpart(str, delims, partno), crc32(str) and md5(str) functions.\n\n" \
"Icu (third party)\n"\
- "Adds partial support for national symbols e.g. ""select lower('٧);"" returns """"\n\n" \
+ "Adds partial support for national symbols e.g. ""select lower('\x042B');"" returns ""\x044B""\n\n" \
"SQLite Workflow Manager adds auxiliary extensions: exec, odbc and transform. Check tool's Wiki to get info about them.\n\n"
@@ -699,8 +710,7 @@ BEGIN
"The type is defined by ""key"" column.\nSet a ""value""-column as null if sometimes generated value should be null.\n" \
"You should restart master to apply changes."
- IDS_WELCOME "-- Welcome!\n" \
- "-- Thanks for choosing sqlite-gui.\n" \
+ IDS_WELCOME "-- Welcome! Thanks for choosing sqlite-gui.\n" \
"-- bookstore.sqlite is a demo database for beginners.\n" \
"-- Push ""Execute"" to get all rows from ""books"" table\n" \
"select * from books;"
@@ -730,7 +740,5 @@ END
IDI_LOGO ICON "resources/logo.ico"
IDB_TOOLBAR BITMAP "resources/toolbar.bmp"
-IDB_BTN_ADD BITMAP "resources/btn_add.bmp"
-IDB_BTN_DELETE BITMAP "resources/btn_delete.bmp"
-IDB_BTN_REFRESH BITMAP "resources/btn_refresh.bmp"
+IDB_TOOLBAR_DATA BITMAP "resources/toolbar_data.bmp"
IDB_DIAGRAM_TOOLBAR BITMAP "resources/toolbar_diagram.bmp"
diff --git a/src/tools.cpp b/src/tools.cpp
index 2710898..6720bf6 100644
--- a/src/tools.cpp
+++ b/src/tools.cpp
@@ -453,8 +453,15 @@ namespace tools {
TCHAR create16[MAX_TEXT_LENGTH]{0};
TCHAR insert16[MAX_TEXT_LENGTH]{0};
GetDlgItemText(hWnd, IDC_DLG_TABLENAME, buf16, 255);
- _stprintf(create16, TEXT("create table \"%s\" ("), buf16);
- _stprintf(insert16, TEXT("insert into \"%s\" ("), buf16);
+
+ TCHAR* schema16 = utils::getName(buf16, true);
+ TCHAR* tablename16 = utils::getName(buf16);
+
+ _stprintf(create16, TEXT("create table \"%s\".\"%s\" ("), schema16, tablename16);
+ _stprintf(insert16, TEXT("insert into \"%s\".\"%s\" ("), schema16, tablename16);
+
+ delete [] tablename16;
+ delete [] schema16;
auto catQuotted = [](TCHAR* a, TCHAR* b) {
_tcscat(a, TEXT("\""));
@@ -693,7 +700,6 @@ namespace tools {
if (!_tcslen(connectionString16))
return MessageBox(0, TEXT("Specify a valid connection string"), NULL, 0);
-
if (Button_GetCheck(GetDlgItem(hWnd, IDC_DLG_RECREATE_TARGET)) == BST_CHECKED) {
TCHAR* schema16 = utils::getName(target16, true);
TCHAR* tablename16 = utils::getName(target16);
@@ -788,7 +794,7 @@ namespace tools {
case WM_COMMAND: {
TCHAR path16[MAX_PATH]{0};
- if (wParam == IDC_DLG_DATABASE_SELECTOR && utils::openFile(path16, TEXT("Databases (*.sqlite, *.sqlite3, *.db)\0*.sqlite;.sqlite3;.id\0All\0*.*\0")))
+ if (wParam == IDC_DLG_DATABASE_SELECTOR && utils::openFile(path16, TEXT("Databases (*.sqlite, *.sqlite3, *.db)\0*.sqlite;*.sqlite3;*.db\0All\0*.*\0")))
SetDlgItemText(hWnd, IDC_DLG_DATABASE, path16);
if (wParam == IDC_DLG_COMPARE_SCHEMA || wParam == IDC_DLG_COMPARE_DATA) {
@@ -1203,6 +1209,8 @@ namespace tools {
return CallWindowProc(cbOldCombobox, hWnd, msg, wParam, lParam);
}
+ // USERDATA = 1 if a last generation is ok
+ // lParam is a target table (optional)
BOOL CALLBACK cbDlgDataGenerator (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_INITDIALOG: {
@@ -1217,15 +1225,32 @@ namespace tools {
if (prefs::get("data-generator-truncate"))
Button_SetCheck(GetDlgItem(hWnd, IDC_DLG_GEN_ISTRUNCATE), BST_CHECKED);
- sqlite3_stmt *stmt;
- if (SQLITE_OK == sqlite3_prepare_v2(db, "select name from sqlite_master where type = 'table' and name <> 'sqlite_sequence' order by 1", -1, &stmt, 0)) {
- while (SQLITE_ROW == sqlite3_step(stmt)) {
- TCHAR* name16 = utils::utf8to16((char *)sqlite3_column_text(stmt, 0));
- ComboBox_AddString(hTable, name16);
- delete [] name16;
+ if (lParam) {
+ ComboBox_AddString(hTable, (TCHAR*)lParam);
+ EnableWindow(hTable, !lParam);
+ } else {
+ sqlite3_stmt *stmt, *stmt2;
+ if (SQLITE_OK == sqlite3_prepare_v2(db,
+ "with t as (select name from pragma_database_list()) " \
+ "select name from t order by iif(name = 'main', 1, name)", -1, &stmt, 0)) {
+ while (SQLITE_ROW == sqlite3_step(stmt)) {
+ char* schema8 = (char *)sqlite3_column_text(stmt, 0);
+ char query8[strlen(schema8) + 1024];
+ sprintf(query8,
+ "select iif('%s' = 'main', name, '%s' || '.' || name) from \"%s\".sqlite_master where type = 'table' and name <> 'sqlite_sequence' order by 1",
+ schema8, schema8, schema8);
+ if (SQLITE_OK == sqlite3_prepare_v2(db, query8, -1, &stmt2, 0)) {
+ while (SQLITE_ROW == sqlite3_step(stmt2)) {
+ TCHAR* name16 = utils::utf8to16((char *)sqlite3_column_text(stmt2, 0));
+ ComboBox_AddString(hTable, name16);
+ delete [] name16;
+ }
+ }
+ sqlite3_finalize(stmt2);
+ }
}
+ sqlite3_finalize(stmt);
}
- sqlite3_finalize(stmt);
ComboBox_SetCurSel(hTable, 0);
if (!GENERATOR_TYPE[0]) {
@@ -1261,6 +1286,7 @@ namespace tools {
}
sqlite3_finalize(stmt);
}
+
SendMessage(hWnd, WMU_TARGET_CHANGED, 0, 0);
SetFocus(hTable);
}
@@ -1275,13 +1301,17 @@ namespace tools {
HWND hColumnsWnd = GetDlgItem(hWnd, IDC_DLG_GEN_COLUMNS);
EnumChildWindows(hColumnsWnd, (WNDENUMPROC)cbEnumChildren, (LPARAM)ACTION_DESTROY);
- TCHAR buf16[255]{0};
+ TCHAR name16[1024]{0};
+ GetDlgItemText(hWnd, IDC_DLG_TABLENAME, name16, 1024);
+ TCHAR* schema16 = utils::getName(name16, true);
+ TCHAR* tablename16 = utils::getName(name16);
+
TCHAR query16[MAX_TEXT_LENGTH]{0};
- GetDlgItemText(hWnd, IDC_DLG_TABLENAME, buf16, 255);
+ _stprintf(query16, TEXT("select name from pragma_table_info(\"%s\") where schema = \"%s\" order by cid"), tablename16, schema16);
+ delete [] tablename16;
+ delete [] schema16;
- _stprintf(query16, TEXT("select name from pragma_table_info(\"%s\") order by cid"), buf16);
char* query8 = utils::utf16to8(query16);
-
sqlite3_stmt *stmt;
if (SQLITE_OK == sqlite3_prepare_v2(db, query8, -1, &stmt, 0)) {
int rowNo = 0;
@@ -1397,7 +1427,7 @@ namespace tools {
SendMessage(hWnd, WMU_TARGET_CHANGED, 0, 0);
if (wParam == IDC_DLG_CANCEL || wParam == IDCANCEL) {
- EndDialog(hWnd, DLG_CANCEL);
+ EndDialog(hWnd, GetWindowLong(hWnd, GWL_USERDATA) ? DLG_OK : DLG_CANCEL);
}
if (wParam == IDC_DLG_GEN_DICTIONARY) {
@@ -1418,12 +1448,18 @@ namespace tools {
if (isTruncate && MessageBox(hWnd, TEXT("All data from table will be erased. Continue?"), TEXT("Confirmation"), MB_OKCANCEL | MB_ICONASTERISK) != IDOK)
return true;
- TCHAR table16[128]{0};
- GetDlgItemText(hWnd, IDC_DLG_TABLENAME, table16, 127);
+ TCHAR name16[1024]{0};
+ GetDlgItemText(hWnd, IDC_DLG_TABLENAME, name16, 1024);
+ TCHAR* schema16 = utils::getName(name16, true);
+ TCHAR* tablename16 = utils::getName(name16);
+
+ char* schema8 = utils::utf16to8(schema16);
+ char* tablename8 = utils::utf16to8(tablename16);
+ delete [] schema16;
+ delete [] tablename16;
- char* table8 = utils::utf16to8(table16);
char query8[MAX_TEXT_LENGTH]{0};
- sprintf(query8, "create table temp.data_generator as select null rownum, t.* from \"%s\" t where 1 = 2", table8);
+ sprintf(query8, "create table temp.data_generator as select null rownum, t.* from \"%s\".\"%s\" t where 1 = 2", schema8, tablename8);
execute(query8);
int rowCount = getDlgItemTextAsNumber(hWnd, IDC_DLG_GEN_ROW_COUNT);
@@ -1475,7 +1511,7 @@ namespace tools {
"series(val) as (select 1 union all select val + 1 from series limit (select ceil(%i.0/count(1)) from t)), " \
"t2 as (select t.value FROM t, series order by random()), " \
"t3 as (select rownum(1) rownum, t2.value from t2 order by 1 limit %i)"
- "update temp.data_generator set \"%s\" = (select value from t3 where t3.rownum = temp.data_generator.rownum)"),
+ "update temp.data_generator set \"%s\" = t3.value from t3 where t3.rownum = temp.data_generator.rownum"),
refcolumn16, reftable16, rowCount, rowCount, name16);
}
@@ -1509,22 +1545,24 @@ namespace tools {
hColumnWnd = GetWindow(hColumnWnd, GW_HWNDNEXT);
}
-
prefs::set("data-generator-row-count", rowCount);
prefs::set("data-generator-truncate", +isTruncate);
if (isTruncate) {
- sprintf(query8, "delete from \"%s\"", table8);
+ sprintf(query8, "delete from \"%s\".\"%s\"", schema8, tablename8);
execute(query8);
}
- snprintf(query8, MAX_TEXT_LENGTH, "insert into \"%s\" (%s) select %s from temp.data_generator", table8, columns8, columns8);
- if (execute(query8))
+ snprintf(query8, MAX_TEXT_LENGTH, "insert into \"%s\".\"%s\" (%s) select %s from temp.data_generator", schema8, tablename8, columns8, columns8);
+ int rc = execute(query8);
+ if (rc)
MessageBox(hWnd, TEXT("Done!"), TEXT("Info"), MB_OK);
else
showDbError(hWnd);
+ SetWindowLong(hWnd, GWL_USERDATA, rc);
- delete [] table8;
+ delete [] schema8;
+ delete [] tablename8;
}
}
break;
@@ -1659,7 +1697,9 @@ namespace tools {
GetWindowText(hWnd, table16, 255);
char* table8 = utils::utf16to8(table16);
RECT rc = {pos.x, pos.y, rcSize.right - rcSize.left, rcSize.bottom - rcSize.top};
+ prefs::setSyncMode(0);
prefs::setDiagramRect(dbname8, table8, rc);
+ prefs::setSyncMode(1);
delete [] table8;
}
@@ -1801,7 +1841,9 @@ namespace tools {
}
sqlite3_finalize(stmt);
+ prefs::setSyncMode(0);
EnumChildWindows(hWnd, (WNDENUMPROC)cbEnumChildren, (LPARAM)ACTION_SETDEFFONT);
+ prefs::setSyncMode(1);
SetWindowPos(hWnd, 0, prefs::get("x") + 30, prefs::get("y") + 70, prefs::get("width") - 60, prefs::get("height") - 100, SWP_NOZORDER);
ShowWindow (hWnd, prefs::get("maximized") == 1 ? SW_MAXIMIZE : SW_SHOW);
@@ -1829,6 +1871,7 @@ namespace tools {
int dy = cursor.y - GET_Y_LPARAM(lParam);
if (isMove && (dx != 0 ||dy != 0)) {
+ prefs::setSyncMode(0);
int tblNo = 0;
while(HWND hTableWnd = GetDlgItem(hWnd, IDC_DATABASE_DIAGRAM_TABLE + tblNo)) {
RECT rc;
@@ -1838,6 +1881,7 @@ namespace tools {
SetWindowPos(hTableWnd, 0, p.x - dx, p.y - dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
tblNo++;
}
+ prefs::setSyncMode(1);
}
isMove = false;
diff --git a/src/utils.cpp b/src/utils.cpp
index ee30d6f..ea7777f 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -136,6 +136,20 @@ namespace utils {
CloseClipboard();
}
+ TCHAR* getClipboardText() {
+ if (OpenClipboard(NULL)) {
+ HANDLE clip = GetClipboardData(CF_UNICODETEXT);
+ TCHAR* str = (LPWSTR)GlobalLock(clip);
+ TCHAR* res = new TCHAR[_tcslen(str) + 1]{0};
+ _tcscpy(res, str);
+ GlobalUnlock(clip);
+ CloseClipboard();
+ return res;
+ }
+
+ return new TCHAR[1]{0};
+ }
+
int openFile(TCHAR* path, const TCHAR* filter) {
OPENFILENAME ofn = {0};
diff --git a/src/utils.h b/src/utils.h
index a23e409..c2b5f59 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -16,6 +16,7 @@ namespace utils {
char* utf16to8(const TCHAR* in);
void setClipboardText(const TCHAR* text);
+ TCHAR* getClipboardText();
int openFile(TCHAR* path, const TCHAR* filter);
int saveFile(TCHAR* path, const TCHAR* filter);
bool isFileExists(const TCHAR* path);