Added the query name to history entries. Please note that history entries are not modified if user saves [Query 1] to file [foo.sql]. I don't think that would be practical.
On Wed, Feb 10, 2016 at 8:28 AM, Dave Page <dp...@pgadmin.org> wrote: > Hi > > On Wed, Feb 10, 2016 at 12:14 AM, Sergey Busel <sbu...@gmail.com> wrote: > >> Dave, >> >> Here is a patch that does display the query tab name in the title bar of >> the output pane. It seems to work with loading and saving the perspective, >> too. The trick is to restore the original text on the output pane before >> loading and saving the perspective, and put the query name back in there >> right after. >> >> Attached is the full patch, not the diff from the previous patch I sent. >> Let me know if you have other suggestions. >> > > That seems to solve the problem nicely :-) - Thanks! > > It does lead to one other issue that I can see - the History tab on the > results pane now shows the history for all query tabs, which seems a little > odd given that the other 3 tabs on the results panel are query tab > specific. Unless there are better ideas, I think the best way to fix this > is to include the current tab name in the history, e.g. > > -- Executing query [Query 1]: > SELECT version(); > Total query runtime: 16 msec > 1 row retrieved. > > -- Executing query [Query 2]: > SELECT * FROM pg_class > Total query runtime: 53 msec > 311 rows retrieved. > > -- Executing query [foo.sql]: > SELECT * from pg_attribute > Total query runtime: 245 msec > 2399 rows retrieved. > > What do you think? > > >> Regards. >> >> On Fri, Feb 5, 2016 at 7:46 AM, Dave Page <dp...@pgadmin.org> wrote: >> >>> On Wed, Feb 3, 2016 at 3:07 AM, Sergey Busel <sbu...@gmail.com> wrote: >>> > - Removed unused/commented code. >>> > - Tab names now reflect the file name, if such is associated with a >>> tab. >>> > - Removed the "Close Tab" menu item. Added X button to the active tab. >>> > - To tell the user which tab results are related to and to avoid >>> messing >>> > with perspective, the name of the related tab is now displayed as "Data >>> > Output [Query 1]" in the output pane. If the tab is named after a >>> file, file >>> > name will display in the square brackets. If the file name is longer >>> then 15 >>> > chars, it will be truncated to 15 chars. >>> > >>> > Let me know any other suggestions you may have. >>> >>> Thanks - this seems to be working nicely for me. It would be good if >>> the query name could be displayed in the title bar of the output pane >>> rather than on the results tab (because it really does apply to all >>> tabs), but I don't see any sensible way to do that given the weird way >>> that wxAUI stores it's perspectives. >>> >>> Ashesh, any ideas? >>> >>> -- >>> Dave Page >>> Blog: http://pgsnake.blogspot.com >>> Twitter: @pgsnake >>> >>> EnterpriseDB UK: http://www.enterprisedb.com >>> The Enterprise PostgreSQL Company >>> >> >> > > > -- > Dave Page > Blog: http://pgsnake.blogspot.com > Twitter: @pgsnake > > EnterpriseDB UK: http://www.enterprisedb.com > The Enterprise PostgreSQL Company >
diff -aur --exclude-from expats /home/sergey/c/pgadmin3-1.22.0/pgadmin/ctl/ctlSQLBox.cpp /home/sergey/c/pgadmin3-1.22.0-dev/pgadmin/ctl/ctlSQLBox.cpp --- /home/sergey/c/pgadmin3-1.22.0/pgadmin/ctl/ctlSQLBox.cpp 2016-01-04 07:03:33.000000000 -0600 +++ /home/sergey/c/pgadmin3-1.22.0-dev/pgadmin/ctl/ctlSQLBox.cpp 2016-02-09 17:27:05.177452723 -0600 @@ -184,6 +184,87 @@ m_database = db; } +void ctlSQLBox::SetChanged(bool b) +{ + if (m_changed != b) + { + m_changed = b; + UpdateTitle(); + } +} + +bool ctlSQLBox::IsChanged() +{ + return m_changed; +} + +void ctlSQLBox::SetOrigin(int origin) +{ + m_origin = origin; +} + +int ctlSQLBox::GetOrigin() +{ + return m_origin; +} + +void ctlSQLBox::SetFilename(wxString &filename) +{ + m_filename = filename; + UpdateTitle(); +} + +wxString ctlSQLBox::GetFilename() +{ + return m_filename; +} + +void ctlSQLBox::SetTitle(wxString &title) +{ + m_title = title; +} + +wxString ctlSQLBox::GetTitle(bool withChangeInd) +{ + wxString title = m_title; + wxString chStr; + if (!withChangeInd) + { + chStr = GetChangeIndicator(); + if (title.EndsWith(chStr)) + title = title.Mid(0, title.Len() - chStr.Len()); + } + return title; +} + +wxString ctlSQLBox::GetChangeIndicator() +{ + if (m_changestr.IsEmpty()) + m_changestr = _("*"); + return m_changestr; +} + +void ctlSQLBox::UpdateTitle() +{ + bool hasCh = false; + wxString chStr = GetChangeIndicator(); + wxString title = GetFilename(); + + if (!title.IsEmpty()) + title = wxFileName::FileName(title).GetFullName(); + else + title = GetTitle(); + + hasCh = title.EndsWith(chStr); + + if (IsChanged() && !hasCh) + title = title + chStr; + else if (!IsChanged() && hasCh) + title = title.Mid(0, title.Len() - chStr.Len()); + + SetTitle(title); +} + void ctlSQLBox::OnSearchReplace(wxCommandEvent &ev) { if (!m_dlgFindReplace) diff -aur --exclude-from expats /home/sergey/c/pgadmin3-1.22.0/pgadmin/frm/frmQuery.cpp /home/sergey/c/pgadmin3-1.22.0-dev/pgadmin/frm/frmQuery.cpp --- /home/sergey/c/pgadmin3-1.22.0/pgadmin/frm/frmQuery.cpp 2016-01-04 07:03:33.000000000 -0600 +++ /home/sergey/c/pgadmin3-1.22.0-dev/pgadmin/frm/frmQuery.cpp 2016-02-11 08:10:20.650395746 -0600 @@ -84,6 +84,7 @@ #define CTRLID_CONNECTION 4200 #define CTRLID_DATABASELABEL 4201 +#define CTL_SQLQUERYBOOK 4202 #define XML_FROM_WXSTRING(s) ((const xmlChar *)(const char *)s.mb_str(wxConvUTF8)) #define WXSTRING_FROM_XML(s) wxString((char *)s, wxConvUTF8) @@ -106,6 +107,7 @@ EVT_MENU(MNU_OPEN, frmQuery::OnOpen) EVT_MENU(MNU_SAVE, frmQuery::OnSave) EVT_MENU(MNU_SAVEAS, frmQuery::OnSaveAs) + EVT_MENU(MNU_NEWSQLTAB, frmQuery::OnSqlBookAddPage) EVT_MENU(MNU_EXPORT, frmQuery::OnExport) EVT_MENU(MNU_SAVEAS_IMAGE_GQB, frmQuery::SaveExplainAsImage) EVT_MENU(MNU_SAVEAS_IMAGE_EXPLAIN, frmQuery::SaveExplainAsImage) @@ -170,6 +172,9 @@ EVT_PGQUERYRESULT(QUERY_COMPLETE, frmQuery::OnQueryComplete) EVT_MENU(PGSCRIPT_COMPLETE, frmQuery::OnScriptComplete) EVT_AUINOTEBOOK_PAGE_CHANGED(CTL_NTBKCENTER, frmQuery::OnChangeNotebook) + EVT_AUINOTEBOOK_PAGE_CHANGED(CTL_SQLQUERYBOOK, frmQuery::OnSqlBookPageChanged) + EVT_AUINOTEBOOK_PAGE_CHANGING(CTL_SQLQUERYBOOK, frmQuery::OnSqlBookPageChanging) + EVT_AUINOTEBOOK_PAGE_CLOSE(CTL_SQLQUERYBOOK, frmQuery::OnSqlBookPageClose) EVT_SPLITTER_SASH_POS_CHANGED(GQB_HORZ_SASH, frmQuery::OnResizeHorizontally) EVT_BUTTON(CTL_DELETECURRENTBTN, frmQuery::OnDeleteCurrent) EVT_BUTTON(CTL_DELETEALLBTN, frmQuery::OnDeleteAll) @@ -235,7 +240,6 @@ loading = true; closing = false; - origin = ORIGIN_MANUAL; dlgName = wxT("frmQuery"); recentKey = wxT("RecentFiles"); @@ -263,6 +267,11 @@ saveasImageMenu->Append(MNU_SAVEAS_IMAGE_GQB, _("Graphical Query (image)"), _("Save Graphical Query as an image")); saveasImageMenu->Append(MNU_SAVEAS_IMAGE_EXPLAIN, _("Explain (image)"), _("Save output of Explain as an image")); fileMenu->Append(wxID_ANY, _("Save as"), saveasImageMenu); + + // SQL tabs related menu items + fileMenu->AppendSeparator(); + fileMenu->Append(MNU_NEWSQLTAB, _("New SQL &tab"), _("Open a new query tab")); + fileMenu->AppendSeparator(); fileMenu->Append(MNU_EXPORT, _("&Export..."), _("Export data to file")); fileMenu->Append(MNU_QUICKREPORT, _("&Quick report..."), _("Run a quick report...")); @@ -494,13 +503,14 @@ // This one will contain the SQL box wxBoxSizer *boxSQL = new wxBoxSizer(wxHORIZONTAL); - // Query box - sqlQuery = new ctlSQLBox(pnlQuery, CTL_SQLQUERY, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxSIMPLE_BORDER | wxTE_RICH2); - sqlQuery->SetDatabase(conn); - sqlQuery->SetMarginWidth(1, 16); - sqlQuery->SetDropTarget(new DnDFile(this)); - SetEOLModeDisplay(sqlQuery->GetEOLMode()); - boxSQL->Add(sqlQuery, 1, wxEXPAND | wxRIGHT | wxLEFT | wxBOTTOM, 1); + // Use sqlQueryBook instead of sqlQuery and put the book inside boxSQL sizer. + // We don't add any SQL tabs until all menu items are initialized from settings. + sqlQueryBook = new ctlAuiNotebook(pnlQuery, CTL_SQLQUERYBOOK, wxDefaultPosition, wxDefaultSize, wxAUI_NB_TOP | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE | wxAUI_NB_SCROLL_BUTTONS | wxAUI_NB_CLOSE_ON_ACTIVE_TAB | wxAUI_NB_WINDOWLIST_BUTTON); + sqlQueryCounter = 0; + sqlQueryExec = NULL; + sqlQueryExecLast = NULL; + + boxSQL->Add(sqlQueryBook, 1, wxEXPAND | wxRIGHT | wxLEFT | wxBOTTOM, 1); boxQuery->Add(boxSQL, 1, wxEXPAND | wxRIGHT | wxLEFT | wxBOTTOM, 1); @@ -535,8 +545,6 @@ outputPane->AddPage(msgResult, _("Messages")); outputPane->AddPage(msgHistory, _("History")); - sqlQuery->Connect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); - sqlQuery->Connect(wxID_ANY, wxEVT_KILL_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); sqlResult->Connect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); msgResult->Connect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); msgHistory->Connect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); @@ -586,47 +594,30 @@ // Auto indent settings->Read(wxT("frmQuery/AutoIndent"), &bVal, true); editMenu->Check(MNU_AUTOINDENT, bVal); - if (bVal) - sqlQuery->SetAutoIndent(true); - else - sqlQuery->SetAutoIndent(false); // Word wrap settings->Read(wxT("frmQuery/WordWrap"), &bVal, false); viewMenu->Check(MNU_WORDWRAP, bVal); - if (bVal) - sqlQuery->SetWrapMode(wxSTC_WRAP_WORD); - else - sqlQuery->SetWrapMode(wxSTC_WRAP_NONE); // Indent Guides settings->Read(wxT("frmQuery/ShowIndentGuides"), &bVal, false); viewMenu->Check(MNU_SHOWINDENTGUIDES, bVal); - if (bVal) - sqlQuery->SetIndentationGuides(true); - else - sqlQuery->SetIndentationGuides(false); // Whitespace settings->Read(wxT("frmQuery/ShowWhitespace"), &bVal, false); viewMenu->Check(MNU_SHOWWHITESPACE, bVal); - if (bVal) - sqlQuery->SetViewWhiteSpace(wxSTC_WS_VISIBLEALWAYS); - else - sqlQuery->SetViewWhiteSpace(wxSTC_WS_INVISIBLE); // Line ends settings->Read(wxT("frmQuery/ShowLineEnds"), &bVal, false); viewMenu->Check(MNU_SHOWLINEENDS, bVal); - if (bVal) - sqlQuery->SetViewEOL(1); - else - sqlQuery->SetViewEOL(0); // Line number settings->Read(wxT("frmQuery/ShowLineNumber"), &bVal, false); viewMenu->Check(MNU_SHOWLINENUMBER, bVal); + // Create the SQL box. After this, sqlQuery variable can be used. + SqlBookAddPage(); + if (!file.IsEmpty() && wxFileName::FileExists(file)) { wxFileName fn = file; @@ -641,12 +632,13 @@ sqlQuery->SetText(query); sqlQuery->Colourise(0, query.Length()); wxSafeYield(); // needed to process sqlQuery modify event - changed = false; - origin = ORIGIN_INITIAL; + sqlQuery->SetChanged(false); + sqlQuery->SetOrigin(ORIGIN_INITIAL); /* _title if not empty should contain displayName of base object for the query. It's pretty good for a proposed filename if the user chooses to Save As. */ lastFilename = _title; setExtendedTitle(); + SqlBookUpdatePageTitle(); } updateMenu(); @@ -818,6 +810,9 @@ void frmQuery::OnDefaultView(wxCommandEvent &event) { + // Reset captions to whatever AuiManager expects in perspective + BeginPerspectiveChange(); + manager.LoadPerspective(FRMQUERY_DEFAULT_PERSPECTIVE, true); // Reset the captions for the current language @@ -827,6 +822,8 @@ manager.GetPane(wxT("outputPane")).Caption(_("Output pane")); manager.GetPane(wxT("scratchPad")).Caption(_("Scratch pad")); + EndPerspectiveChange(false); + manager.Update(); // Sync the View menu options @@ -860,10 +857,7 @@ settings->WriteBool(wxT("frmQuery/AutoIndent"), editMenu->IsChecked(MNU_AUTOINDENT)); - if (editMenu->IsChecked(MNU_AUTOINDENT)) - sqlQuery->SetAutoIndent(true); - else - sqlQuery->SetAutoIndent(false); + SqlBookSetAutoIndent(event.IsChecked()); } @@ -873,10 +867,7 @@ settings->WriteBool(wxT("frmQuery/WordWrap"), viewMenu->IsChecked(MNU_WORDWRAP)); - if (viewMenu->IsChecked(MNU_WORDWRAP)) - sqlQuery->SetWrapMode(wxSTC_WRAP_WORD); - else - sqlQuery->SetWrapMode(wxSTC_WRAP_NONE); + SqlBookSetWrapMode(event.IsChecked()); } @@ -886,10 +877,7 @@ settings->WriteBool(wxT("frmQuery/ShowIndentGuides"), viewMenu->IsChecked(MNU_SHOWINDENTGUIDES)); - if (viewMenu->IsChecked(MNU_SHOWINDENTGUIDES)) - sqlQuery->SetIndentationGuides(true); - else - sqlQuery->SetIndentationGuides(false); + SqlBookSetIndentGuides(event.IsChecked()); } @@ -899,10 +887,7 @@ settings->WriteBool(wxT("frmQuery/ShowWhitespace"), viewMenu->IsChecked(MNU_SHOWWHITESPACE)); - if (viewMenu->IsChecked(MNU_SHOWWHITESPACE)) - sqlQuery->SetViewWhiteSpace(wxSTC_WS_VISIBLEALWAYS); - else - sqlQuery->SetViewWhiteSpace(wxSTC_WS_INVISIBLE); + SqlBookSetViewWhiteSpace(event.IsChecked()); } @@ -912,10 +897,7 @@ settings->WriteBool(wxT("frmQuery/ShowLineEnds"), viewMenu->IsChecked(MNU_SHOWLINEENDS)); - if (viewMenu->IsChecked(MNU_SHOWLINEENDS)) - sqlQuery->SetViewEOL(1); - else - sqlQuery->SetViewEOL(0); + SqlBookSetViewEOL(event.IsChecked()); } @@ -925,7 +907,7 @@ settings->WriteBool(wxT("frmQuery/ShowLineNumber"), viewMenu->IsChecked(MNU_SHOWLINENUMBER)); - sqlQuery->UpdateLineNumber(); + SqlBookSetViewLineNumbers(event.IsChecked()); } void frmQuery::OnActivate(wxActivateEvent &event) @@ -1080,6 +1062,7 @@ else { conn = (pgConn *)cbConnection->GetClientData(sel); + SqlBookSetDatabase(conn); sqlResult->SetConnection(conn); pgScript->SetConnection(conn); title = wxT("Query - ") + cbConnection->GetValue(); @@ -1421,17 +1404,18 @@ void frmQuery::setExtendedTitle() { wxString chgStr; - if (changed) + if (sqlQuery->IsChanged()) chgStr = wxT(" *"); - if (lastPath.IsNull()) + wxString filename = sqlQuery->GetFilename(); + if (filename.IsNull()) SetTitle(title + chgStr); else { - SetTitle(title + wxT(" - [") + lastPath + wxT("]") + chgStr); + SetTitle(title + wxT(" - [") + filename + wxT("]") + chgStr); } // Allow to save initial queries though they are not changed - bool enableSave = changed || (origin == ORIGIN_INITIAL); + bool enableSave = sqlQuery->IsChanged() || (sqlQuery->GetOrigin() == ORIGIN_INITIAL); toolBar->EnableTool(MNU_SAVE, enableSave); fileMenu->Enable(MNU_SAVE, enableSave); } @@ -1668,11 +1652,12 @@ bool frmQuery::CheckChanged(bool canVeto) { - if (changed && settings->GetAskSaveConfirmation()) + if (sqlQuery->IsChanged() && settings->GetAskSaveConfirmation()) { - wxString fn; - if (!lastPath.IsNull()) - fn = wxString::Format(_("The text in file %s has changed.\nDo you want to save changes?"), lastPath.c_str()); + wxString fn, filename; + filename = sqlQuery->GetFilename(); + if (!filename.IsNull()) + fn = wxString::Format(_("The text in file %s has changed.\nDo you want to save changes?"), filename.c_str() /*lastPath.c_str()*/); else fn = _("The text has changed.\nDo you want to save changes?"); wxMessageDialog msg(this, fn, _("Query"), @@ -1683,12 +1668,12 @@ switch (msg.ShowModal()) { case wxID_YES: - if (lastPath.IsNull()) + if (filename.IsNull()) OnSaveAs(noEvent); else OnSave(noEvent); - return changed; + return sqlQuery->IsChanged(); case wxID_CANCEL: return true; @@ -1732,7 +1717,7 @@ return; } - if (CheckChanged(event.CanVeto()) && event.CanVeto()) + if (SqlBookClose(event.CanVeto()) && event.CanVeto()) { event.Veto(); return; @@ -1749,7 +1734,7 @@ Hide(); - sqlQuery->Disconnect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); + //sqlQuery->Disconnect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); sqlResult->Disconnect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); msgResult->Disconnect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); msgHistory->Disconnect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); @@ -1776,15 +1761,16 @@ // Sometimes there come events 20 and 520 AFTER the initial query was set by constructor. // Their occurrence is related to query's size and possibly international characters in it (??) // Filter them out to keep "initial" origin of query text. - (origin != ORIGIN_INITIAL || (event.m_modificationType != 20 && event.m_modificationType != 520))) + (sqlQuery->GetOrigin() != ORIGIN_INITIAL || (event.m_modificationType != 20 && event.m_modificationType != 520))) { // This is the default change origin. // In other cases the changer function will reset it after this event. - origin = ORIGIN_MANUAL; - if (!changed) + sqlQuery->SetOrigin(ORIGIN_MANUAL); + if (!sqlQuery->IsChanged()) { - changed = true; + sqlQuery->SetChanged(true); setExtendedTitle(); + SqlBookUpdatePageTitle(); } } // do not allow update of model size of GQB on input (key press) of each @@ -1826,9 +1812,11 @@ sqlQuery->Colourise(0, str.Length()); sqlQuery->EmptyUndoBuffer(); wxSafeYield(); // needed to process sqlQuery modify event - changed = false; - origin = ORIGIN_FILE; + sqlQuery->SetFilename(lastPath); + sqlQuery->SetChanged(false); + sqlQuery->SetOrigin(ORIGIN_FILE); setExtendedTitle(); + SqlBookUpdatePageTitle(); SetLineEndingStyle(); UpdateRecentFiles(true); if(mainForm != NULL) @@ -1881,26 +1869,28 @@ void frmQuery::OnSave(wxCommandEvent &event) { bool modeUnicode = settings->GetUnicodeFile(); + wxString filename = sqlQuery->GetFilename(); - if (lastPath.IsNull()) + if (filename.IsNull()) { OnSaveAs(event); return; } - wxUtfFile file(lastPath, wxFile::write, modeUnicode ? wxFONTENCODING_UTF8 : wxFONTENCODING_DEFAULT); + wxUtfFile file(filename, wxFile::write, modeUnicode ? wxFONTENCODING_UTF8 : wxFONTENCODING_DEFAULT); if (file.IsOpened()) { if ((file.Write(sqlQuery->GetText()) == 0) && (!modeUnicode)) wxMessageBox(_("Query text incomplete.\nQuery contained characters that could not be converted to the local charset.\nPlease correct the data or try using UTF8 instead.")); file.Close(); - changed = false; + sqlQuery->SetChanged(false); setExtendedTitle(); UpdateRecentFiles(); + SqlBookUpdatePageTitle(); } else { - wxLogError(__("Could not write the file %s: Errcode=%d."), lastPath.c_str(), wxSysErrorCode()); + wxLogError(__("Could not write the file %s: Errcode=%d."), filename.c_str(), wxSysErrorCode()); } } @@ -1924,7 +1914,7 @@ { wxMessageBox(_("This file contains mixed line endings. They will be converted to the current setting."), _("Warning"), wxICON_INFORMATION | wxOK); sqlQuery->ConvertEOLs(mode); - changed = true; + sqlQuery->SetChanged(true); setExtendedTitle(); updateMenu(); } @@ -1940,27 +1930,7 @@ // Now set the status text, menu options, and the mode sqlQuery->SetEOLMode(mode); - switch(mode) - { - - case wxSTC_EOL_LF: - lineEndMenu->Check(MNU_LF, true); - SetStatusText(_("Unix"), STATUSPOS_FORMAT); - break; - - case wxSTC_EOL_CRLF: - lineEndMenu->Check(MNU_CRLF, true); - SetStatusText(_("DOS"), STATUSPOS_FORMAT); - break; - - case wxSTC_EOL_CR: - lineEndMenu->Check(MNU_CR, true); - SetStatusText(_("Mac"), STATUSPOS_FORMAT); - break; - - default: - wxLogError(wxT("Someone created a new line ending style! Run, run for your lives!!")); - } + SetEOLModeDisplay(mode); delete reCRLF; delete reCR; @@ -1992,12 +1962,14 @@ SetEOLModeDisplay(mode); - if (!changed) + if (!sqlQuery->IsChanged()) { - changed = true; + sqlQuery->SetChanged(true); setExtendedTitle(); } + setExtendedTitle(); + // TODO: Figure out why this is here? pgScript->SetConnection(conn); } @@ -2031,11 +2003,16 @@ void frmQuery::OnSaveAs(wxCommandEvent &event) { + wxString filename; + filename = sqlQuery->GetFilename(); + if (filename.IsNull()) + filename = lastFilename; + #ifdef __WXMSW__ - wxFileDialog *dlg = new wxFileDialog(this, _("Save query file as"), lastDir, lastFilename, + wxFileDialog *dlg = new wxFileDialog(this, _("Save query file as"), lastDir, filename, /*lastFilename,*/ _("Query files (*.sql)|*.sql|All files (*.*)|*.*"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); #else - wxFileDialog *dlg = new wxFileDialog(this, _("Save query file as"), lastDir, lastFilename, + wxFileDialog *dlg = new wxFileDialog(this, _("Save query file as"), lastDir, filename, /*lastFilename,*/ _("Query files (*.sql)|*.sql|All files (*)|*"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); #endif if (dlg->ShowModal() == wxID_OK) @@ -2069,14 +2046,17 @@ if ((file.Write(sqlQuery->GetText()) == 0) && (!lastFileFormat)) wxMessageBox(_("Query text incomplete.\nQuery contained characters that could not be converted to the local charset.\nPlease correct the data or try using UTF8 instead.")); file.Close(); - changed = false; + sqlQuery->SetChanged(false); + sqlQuery->SetFilename(lastPath); // Forget about Initial origin thus making "Save" button behave as usual // (be enabled/disabled according to dirty flag only). - if (origin == ORIGIN_INITIAL) - origin = ORIGIN_FILE; + if (sqlQuery->GetOrigin() == ORIGIN_INITIAL) + sqlQuery->SetOrigin(ORIGIN_FILE); setExtendedTitle(); + SqlBookUpdatePageTitle(); + SetOutputPaneCaption(true); UpdateRecentFiles(); fileMenu->Enable(MNU_RECENT, (recentFileMenu->GetMenuItemCount() > 0)); } @@ -2257,7 +2237,7 @@ // Only prompt the user if the dirty flag is set, and last modification wasn't from GQB, // and the textbox is not empty, and the new query is different. - if(changed && origin != ORIGIN_GQB && + if (sqlQuery->IsChanged() && sqlQuery->GetOrigin() != ORIGIN_GQB && !sqlQuery->GetText().Trim().IsEmpty() && sqlQuery->GetText() != newQuery + wxT("\n")) { wxString fn; @@ -2267,7 +2247,7 @@ fn = _("The generated SQL query has changed.\nDo you want to update it?"); wxMessageDialog msg(this, fn, _("Query"), wxYES_NO | wxICON_EXCLAMATION); - if(msg.ShowModal() == wxID_YES && changed) + if(msg.ShowModal() == wxID_YES && sqlQuery->IsChanged()) { canGenerate = true; } @@ -2287,8 +2267,8 @@ sqlQuery->Colourise(0, sqlQuery->GetText().Length()); wxSafeYield(); // needed to process sqlQuery modify event sqlNotebook->SetSelection(0); - changed = true; - origin = ORIGIN_GQB; + sqlQuery->SetChanged(true); + sqlQuery->SetOrigin(ORIGIN_GQB); setExtendedTitle(); gqbUpdateRunning = false; @@ -2437,6 +2417,7 @@ } query.Replace(wxT("$SELECTION$"), selection); } + execQuery(query); sqlQuery->SetFocus(); } @@ -2495,7 +2476,7 @@ sqlQuery->StartStyling(0, wxSTC_INDICS_MASK); sqlQuery->SetStyling(sqlQuery->GetText().Length(), 0); - if (!changed) + if (!sqlQuery->IsChanged()) setExtendedTitle(); aborted = false; @@ -2519,6 +2500,14 @@ } } + // Remember the tab from which execute was called. By the time query completes, SQL tab selection may change. + sqlQueryExec = sqlQuery; + // Because the output pane is clear during query execution, we clear the result source title on Output Pane. + sqlQueryExecLast = NULL; + SetOutputPaneCaption(true); + + ClearResultSource(); + // We must do this lot before the query starts, otherwise // it might not happen once the main thread gets busy with // other stuff. @@ -2528,7 +2517,7 @@ msgResult->Clear(); msgResult->SetFont(settings->GetSQLFont()); - msgHistory->AppendText(_("-- Executing query:\n")); + msgHistory->AppendText(wxString::Format(_("-- Executing query [%s]:\n"), sqlQueryExec->GetTitle(false).c_str())); msgHistory->AppendText(query); msgHistory->AppendText(wxT("\n")); Update(); @@ -2852,9 +2841,9 @@ if (!errMsg2.IsEmpty()) showMessage(errMsg2); - if (errPos > 0) + if (errPos > 0 && sqlQueryExec != NULL) { - int selStart = sqlQuery->GetSelectionStart(), selEnd = sqlQuery->GetSelectionEnd(); + int selStart = sqlQueryExec->GetSelectionStart(), selEnd = sqlQueryExec->GetSelectionEnd(); if (selStart == selEnd) selStart = 0; @@ -2862,29 +2851,29 @@ // Set an indicator on the error word (break on any kind of bracket, a space or full stop) int sPos = errPos + selStart - 1, wEnd = 1; - sqlQuery->StartStyling(sPos, wxSTC_INDICS_MASK); - int c = sqlQuery->GetCharAt(sPos + wEnd); - size_t len = sqlQuery->GetText().Length(); + sqlQueryExec->StartStyling(sPos, wxSTC_INDICS_MASK); + int c = sqlQueryExec->GetCharAt(sPos + wEnd); + size_t len = sqlQueryExec->GetText().Length(); while(c != ' ' && c != '(' && c != '{' && c != '[' && c != '.' && (unsigned int)(sPos + wEnd) < len) { wEnd++; - c = sqlQuery->GetCharAt(sPos + wEnd); + c = sqlQueryExec->GetCharAt(sPos + wEnd); } - sqlQuery->SetStyling(wEnd, wxSTC_INDIC0_MASK); + sqlQueryExec->SetStyling(wEnd, wxSTC_INDIC0_MASK); - int line = 0, maxLine = sqlQuery->GetLineCount(); - while (line < maxLine && sqlQuery->GetLineEndPosition(line) < errPos + selStart + 1) + int line = 0, maxLine = sqlQueryExec->GetLineCount(); + while (line < maxLine && sqlQueryExec->GetLineEndPosition(line) < errPos + selStart + 1) line++; if (line < maxLine) { - sqlQuery->GotoPos(sPos); - sqlQuery->MarkerAdd(line, 0); + sqlQueryExec->GotoPos(sPos); + sqlQueryExec->MarkerAdd(line, 0); - if (!changed) + if (!sqlQueryExec->IsChanged()) setExtendedTitle(); - sqlQuery->EnsureVisible(line); + sqlQueryExec->EnsureVisible(line); } } } @@ -2981,9 +2970,9 @@ if (sqlResult->RunStatus() == PGRES_TUPLES_OK || sqlResult->RunStatus() == PGRES_COMMAND_OK) { // Get the executed query - wxString executedQuery = sqlQuery->GetSelectedText(); + wxString executedQuery = sqlQueryExec->GetSelectedText(); if (executedQuery.IsNull()) - executedQuery = sqlQuery->GetText(); + executedQuery = sqlQueryExec->GetText(); // Same query, but without return feeds and carriage returns wxString executedQueryWithoutReturns = executedQuery; @@ -3176,9 +3165,44 @@ updateMenu(); } + // Change the output pane caption so the user knows which tab the result came from + sqlQueryExecLast = sqlQueryExec; + SetOutputPaneCaption(true); + + sqlQueryExec = NULL; sqlQuery->SetFocus(); } +void frmQuery::SetResultSource() +{ + // Change the tab text so the user knows which tab the result came from + if (sqlQueryExec != NULL) + { + wxString title = sqlQueryExec->GetTitle(); + wxString chStr = sqlQueryExec->GetChangeIndicator(); + if (title.EndsWith(chStr)) + title = title.Mid(0, title.Len() - chStr.Len()); + if (title.Len() > 18) + title = title.Mid(0, 15) + _("..."); + + wxString text = outputPane->GetPageText(0); + wxString newtext = wxString::Format(_("%s [%s]"), text.c_str(), title.c_str()); + outputPane->SetPageText(0, newtext); + } +} + +void frmQuery::ClearResultSource() +{ + // Clear previous indicator of which tab results came from. + wxString text = outputPane->GetPageText(0); + int idx = text.Find('['); + if (idx != wxNOT_FOUND) + { + text = text.Mid(0, idx - 1); + outputPane->SetPageText(0, text); + } +} + void frmQuery::OnTimer(wxTimerEvent &event) { @@ -3478,8 +3502,8 @@ sqlQuery->SetText(query); sqlQuery->Colourise(0, query.Length()); wxSafeYield(); // needed to process sqlQuery modify event - changed = true; - origin = ORIGIN_HISTORY; + sqlQuery->SetChanged(true); + sqlQuery->SetOrigin(ORIGIN_HISTORY); setExtendedTitle(); SetLineEndingStyle(); btnDeleteCurrent->Enable(true); @@ -3523,6 +3547,303 @@ } } +void frmQuery::BeginPerspectiveChange() +{ + manager.GetPane(_("outputPane")).Caption(_("Output pane")); +} + +void frmQuery::EndPerspectiveChange(bool update) +{ + SetOutputPaneCaption(update); +} + +void frmQuery::SetOutputPaneCaption(bool update) +{ + wxString caption; + wxString title; + + if (sqlQueryExecLast == NULL) + caption = _("Output pane"); + else + { + // We don't want to make it look like Output Pane has been changed, + // so request the title without the change indicator + title = sqlQueryExecLast->GetTitle(false); + caption = wxString::Format(_("Output pane [%s]"), title.c_str()); + } + + manager.GetPane(wxT("outputPane")).Caption(caption); + + if (update) + manager.Update(); +} + +// Methods related to SQL tabs // + +void frmQuery::OnSqlBookPageChanged(wxAuiNotebookEvent &event) +{ + // Try to always keep sqlQuery variable pointing to the currently selected SQLBox. + // When closing and removing all tabs, page count may be zero. + if (sqlQueryBook->GetPageCount() > 0) + { + size_t curpage = sqlQueryBook->GetSelection(); + sqlQuery = (ctlSQLBox *) sqlQueryBook->GetPage(curpage); + + // Update UI with chosen query's info + SetEOLModeDisplay(sqlQuery->GetEOLMode()); + setExtendedTitle(); + } + else + { + // This should help us find bugs (such as using sqlQuery after closing all tabs) much faster. + sqlQuery = NULL; + } +} + +void frmQuery::OnSqlBookPageChanging(wxAuiNotebookEvent &event) +{ + // Veto event while page change is prohibited. + if (!SqlBookCanChangePage()) + { + event.Veto(); + wxMessageBox(_("Cannot change to selected SQL tab now. Try again a bit later.")); + } +} + +void frmQuery::OnSqlBookAddPage(wxCommandEvent &event) +{ + if (SqlBookCanChangePage()) + SqlBookAddPage(); + else + wxMessageBox(_("Cannot add a new SQL tab now. Try again a bit later.")); +} + +void frmQuery::OnSqlBookPageClose(wxAuiNotebookEvent &event) +{ + // Don't allow removal of the last SQL box via user generated event + size_t pagecnt = sqlQueryBook->GetPageCount(); + if (pagecnt == 1) + { + event.Veto(); + wxMessageBox(_("Cannot remove the last SQL tab")); + return; + } + + // Prevent removing the page that is currently being executed + if (sqlQueryExec != NULL && sqlQueryExec == sqlQuery) + { + event.Veto(); + wxMessageBox(_("The query on this SQL tab is still running.\nWait for it to finish or cancel it before closing the tab.")); + return; + } + + if (CheckChanged(true)) + { + event.Veto(); + return; + } + + // If removing the tab for which results are displayed, reset the output pane's caption + if (sqlQuery == sqlQueryExecLast) + { + sqlQueryExecLast = NULL; + SetOutputPaneCaption(true); + } + + SqlBookDisconnectPage(); +} + +bool frmQuery::SqlBookCanChangePage() +{ + return !(m_loadingfile || ms_pgScriptRunning); +} + +void frmQuery::SqlBookAddPage() +{ + ctlSQLBox *box; + wxString caption; + bool bVal; + + // All SQL boxes use the same wxID, CTL_SQLQUERY. + // This should probably be changed, but it works for now and has minimal impact on existing code. + box = new ctlSQLBox(sqlQueryBook, CTL_SQLQUERY, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxSIMPLE_BORDER | wxTE_RICH2); + box->SetDatabase(conn); + box->SetMarginWidth(1, 16); + box->SetDropTarget(new DnDFile(this)); + box->SetChanged(false); + box->SetOrigin(ORIGIN_MANUAL); + + bVal = editMenu->IsChecked(MNU_AUTOINDENT); + box->SetAutoIndent(bVal); + + bVal = viewMenu->IsChecked(MNU_WORDWRAP); + box->SetWrapMode(bVal ? wxSTC_WRAP_WORD : wxSTC_WRAP_NONE); + + bVal = viewMenu->IsChecked(MNU_SHOWINDENTGUIDES); + box->SetIndentationGuides(bVal); + + bVal = viewMenu->IsChecked(MNU_SHOWWHITESPACE); + box->SetViewWhiteSpace(bVal ? wxSTC_WS_VISIBLEALWAYS : wxSTC_WS_INVISIBLE); + + bVal = viewMenu->IsChecked(MNU_SHOWLINEENDS); + box->SetViewEOL(bVal ? 1 : 0); + + box->Connect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); + box->Connect(wxID_ANY, wxEVT_KILL_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); + + sqlQueryCounter ++; + caption = wxString::Format(_("Query %i"), sqlQueryCounter); + box->SetTitle(caption); + sqlQueryBook->AddPage(box, caption, true); + + // Probably not needed, as the line above should trigger the PageChange event + sqlQuery = box; +} + +void frmQuery::SqlBookDisconnectPage() +{ + sqlQuery->Disconnect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); + sqlQuery->Disconnect(wxID_ANY, wxEVT_KILL_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); +} + +bool frmQuery::SqlBookRemovePage() +{ + size_t pageidx; + if (sqlQueryBook->GetPageCount() > 0) + { + // If removing the tab for which results are displayed, reset the output pane's caption + if (sqlQuery == sqlQueryExecLast) + { + sqlQueryExecLast = NULL; + SetOutputPaneCaption(true); + } + + SqlBookDisconnectPage(); + pageidx = sqlQueryBook->GetSelection(); + return sqlQueryBook->DeletePage(pageidx); + } + return false; +} + +void frmQuery::SqlBookSetAutoIndent(bool b) +{ + size_t i, cnt; + ctlSQLBox *box; + + for (i = 0, cnt = sqlQueryBook->GetPageCount(); i < cnt; ++i) + { + box = (ctlSQLBox *) sqlQueryBook->GetPage(i); + box->SetAutoIndent(b); + } +} + +void frmQuery::SqlBookSetWrapMode(bool b) +{ + size_t i, cnt; + ctlSQLBox *box; + + for (i = 0, cnt = sqlQueryBook->GetPageCount(); i < cnt; ++i) + { + box = (ctlSQLBox *) sqlQueryBook->GetPage(i); + box->SetWrapMode(b ? wxSTC_WRAP_WORD : wxSTC_WRAP_NONE); + } +} + +void frmQuery::SqlBookSetIndentGuides(bool b) +{ + size_t i, cnt; + ctlSQLBox *box; + + for (i = 0, cnt = sqlQueryBook->GetPageCount(); i < cnt; ++i) + { + box = (ctlSQLBox *) sqlQueryBook->GetPage(i); + box->SetIndentationGuides(b); + } +} + +void frmQuery::SqlBookSetViewWhiteSpace(bool b) +{ + size_t i, cnt; + ctlSQLBox *box; + + for (i = 0, cnt = sqlQueryBook->GetPageCount(); i < cnt; ++i) + { + box = (ctlSQLBox *) sqlQueryBook->GetPage(i); + box->SetViewWhiteSpace(b ? wxSTC_WS_VISIBLEALWAYS : wxSTC_WS_INVISIBLE); + } +} + +void frmQuery::SqlBookSetViewEOL(bool b) +{ + size_t i, cnt; + ctlSQLBox *box; + + for (i = 0, cnt = sqlQueryBook->GetPageCount(); i < cnt; ++i) + { + box = (ctlSQLBox *) sqlQueryBook->GetPage(i); + box->SetViewEOL(b ? 1 : 0); + } +} + +void frmQuery::SqlBookSetViewLineNumbers(bool b) +{ + size_t i, cnt; + ctlSQLBox *box; + + for (i = 0, cnt = sqlQueryBook->GetPageCount(); i < cnt; ++i) + { + box = (ctlSQLBox *) sqlQueryBook->GetPage(i); + box->UpdateLineNumber(); + } +} + +void frmQuery::SqlBookSetDatabase(pgConn *con) +{ + size_t i, cnt; + ctlSQLBox *box; + + for (i = 0, cnt = sqlQueryBook->GetPageCount(); i < cnt; ++i) + { + box = (ctlSQLBox *) sqlQueryBook->GetPage(i); + box->SetDatabase(con); + } +} + +void frmQuery::SqlBookUpdatePageTitle() +{ + size_t index; + wxString title; + + if (sqlQueryBook->GetPageCount() > 0 && sqlQuery != NULL) + { + index = sqlQueryBook->GetPageIndex(sqlQuery); + if (index == wxNOT_FOUND) + return; + + title = sqlQuery->GetTitle(); + if (sqlQueryBook->GetPageText(index) != title) + sqlQueryBook->SetPageText(index, title); + } +} + +// Returns true if any SQL tab attempts to veto the closing, false otherwise. +bool frmQuery::SqlBookClose(bool canVeto) +{ + // Close all tabs one at a time. The deleted tab is always the current one. + // This loop relies on the fact that deleting a tab will invoke PageChange event, + // which in turn will assign another current tab. Hence, the order in which tabs + // are closed is not defined here. + while (sqlQueryBook->GetPageCount() > 0) + { + if (CheckChanged(canVeto)) + return true; + + // Removing the page should select another page and trigger PageChange event. + SqlBookRemovePage(); + } + return false; +} + /////////////////////////////////////////////////////// diff -aur --exclude-from expats /home/sergey/c/pgadmin3-1.22.0/pgadmin/include/ctl/ctlSQLBox.h /home/sergey/c/pgadmin3-1.22.0-dev/pgadmin/include/ctl/ctlSQLBox.h --- /home/sergey/c/pgadmin3-1.22.0/pgadmin/include/ctl/ctlSQLBox.h 2016-01-04 07:03:33.000000000 -0600 +++ /home/sergey/c/pgadmin3-1.22.0-dev/pgadmin/include/ctl/ctlSQLBox.h 2016-02-09 17:10:59.050767933 -0600 @@ -74,11 +74,23 @@ CharacterRange RegexFindText(int minPos, int maxPos, const wxString &text); + // Having multiple SQL tabs warrants the following properties to be tracked per tab + void SetChanged(bool b); + bool IsChanged(); + void SetOrigin(int origin); + int GetOrigin(); + void SetFilename(wxString &filename); + wxString GetFilename(); + void SetTitle(wxString &title); + wxString GetTitle(bool withChangeInd = true); + wxString GetChangeIndicator(); + DECLARE_DYNAMIC_CLASS(ctlSQLBox) DECLARE_EVENT_TABLE() protected: void OnEndProcess(wxProcessEvent &ev); + void UpdateTitle(); sysProcess *process; long processID; @@ -93,6 +105,13 @@ pgConn *m_database; bool m_autoIndent, m_autocompDisabled; + // Variables to track info per SQL box + wxString m_filename; + wxString m_title; + wxString m_changestr; + bool m_changed; + int m_origin; + friend class QueryPrintout; }; diff -aur --exclude-from expats /home/sergey/c/pgadmin3-1.22.0/pgadmin/include/frm/frmQuery.h /home/sergey/c/pgadmin3-1.22.0-dev/pgadmin/include/frm/frmQuery.h --- /home/sergey/c/pgadmin3-1.22.0/pgadmin/include/frm/frmQuery.h 2016-01-04 07:03:33.000000000 -0600 +++ /home/sergey/c/pgadmin3-1.22.0-dev/pgadmin/include/frm/frmQuery.h 2016-02-09 17:03:25.477426091 -0600 @@ -101,11 +101,11 @@ } void SetChanged(bool p_changed) { - changed = p_changed; + sqlQuery->SetChanged(p_changed); } void SetOrigin(int p_origin) { - origin = p_origin; + sqlQuery->SetOrigin(p_origin); } void SetLastPath(wxString p_lastpath) { @@ -135,6 +135,11 @@ wxButton *btnDeleteAll; wxArrayString histoQueries; + ctlAuiNotebook *sqlQueryBook; //container for all SQL tabs + size_t sqlQueryCounter; //for initial tab names + ctlSQLBox *sqlQueryExec; //currently executing SQL tab + ctlSQLBox *sqlQueryExecLast; //output pane shows results for this SQL tab + // Query timing/status update wxTimer timer; wxLongLong elapsedQuery, startTimeQuery; @@ -261,6 +266,33 @@ bool relatesToWindow(wxWindow *which, wxWindow *related); + // Methods related to SQL tabs + void SqlBookAddPage(); + bool SqlBookRemovePage(); + bool SqlBookCanChangePage(); + void SqlBookSetAutoIndent(bool b); + void SqlBookSetWrapMode(bool b); + void SqlBookSetIndentGuides(bool b); + void SqlBookSetViewWhiteSpace(bool b); + void SqlBookSetViewEOL(bool b); + void SqlBookSetViewLineNumbers(bool b); + void SqlBookSetDatabase(pgConn *con); + void SqlBookUpdatePageTitle(); + void SqlBookDisconnectPage(); + bool SqlBookClose(bool canVeto); + // SQL tabs event handlers + void OnSqlBookAddPage(wxCommandEvent &event); + void OnSqlBookPageClose(wxAuiNotebookEvent &event); + void OnSqlBookPageChanged(wxAuiNotebookEvent &event); + void OnSqlBookPageChanging(wxAuiNotebookEvent &event); + + void BeginPerspectiveChange(); + void EndPerspectiveChange(bool update = false); + void SetOutputPaneCaption(bool update = false); + + void SetResultSource(); + void ClearResultSource(); + wxWindow *currentControl(); wxMenu *queryMenu; wxMenu *favouritesMenu; @@ -280,7 +312,7 @@ bool m_loadingfile; // Complements dirty flag, showing last origin of query's modification (see enum ORIGIN_..) - int origin; + //int origin; // A simple mutex-like flag to prevent concurrent script execution. // Required because the pgScript parser isn't currently thread-safe :-( diff -aur --exclude-from expats /home/sergey/c/pgadmin3-1.22.0/pgadmin/include/frm/menu.h /home/sergey/c/pgadmin3-1.22.0-dev/pgadmin/include/frm/menu.h --- /home/sergey/c/pgadmin3-1.22.0/pgadmin/include/frm/menu.h 2016-01-04 07:03:33.000000000 -0600 +++ /home/sergey/c/pgadmin3-1.22.0-dev/pgadmin/include/frm/menu.h 2016-02-02 16:11:28.255332087 -0600 @@ -44,6 +44,7 @@ MNU_OPEN, MNU_SAVE, MNU_SAVEAS, + MNU_NEWSQLTAB, MNU_EXPORT, MNU_OPTIONS, MNU_CUT,
-- Sent via pgadmin-hackers mailing list (pgadmin-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers