Patch file for multiple SQL tabs is attached.

Thank you

On Mon, Feb 1, 2016 at 3:01 AM, Dave Page <dp...@pgadmin.org> wrote:

> On Sun, Jan 31, 2016 at 7:03 PM, Sergey Busel <sbu...@gmail.com> wrote:
> > Hello,
> > It's my first time here and I hope I am sending this to the right mailing
> > list.
> >
> > I am starting to use pgAdmin 3 more and more nowadays and thought that
> > having a multi tabbed interface would be beneficial especially that most
> (if
> > not all) similar tools go that route. Somewhere in the mail archives I've
> > read that tabs are not being implemented because too much code would
> need to
> > be changed. But I thought I'd give it a try anyway.
> >
> > I have implemented SQL tabs in the 1.22.0 version and have been using it
> for
> > a week. Works just fine for me, so I wonder if there is any interest in
> > adding this feature to pgAdmin 3.
> >
> > Brief overview:
> > The changes to existing code were kept to a minimum.
> > All SQL tabs still operate on the same connection and share the same
> result
> > pane.
> > Each tab has it's own dirty flag, EOL style, and file from/to which it
> was
> > loaded/saved.
> >
> > Let me know if anybody is interested.
>
> Feel free to send the patch, and we'll take a look.
>
> Thanks!
>
> --
> 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-01-31 12:09:37.689549967 -0600
@@ -184,6 +184,36 @@
 	m_database = db;
 }
 
+void ctlSQLBox::SetChanged(bool b)
+{
+	m_changed = b;
+}
+
+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;
+}
+
+wxString ctlSQLBox::GetFilename()
+{
+	return m_filename;
+}
+
 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-01 20:37:52.061428472 -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,9 @@
 	EVT_MENU(MNU_OPEN,              frmQuery::OnOpen)
 	EVT_MENU(MNU_SAVE,              frmQuery::OnSave)
 	EVT_MENU(MNU_SAVEAS,            frmQuery::OnSaveAs)
+	// Handlers to add and remove SQL tabs
+	EVT_MENU(MNU_NEWSQLTAB,         frmQuery::OnSqlBookAddPage)
+	EVT_MENU(MNU_CLOSESQLTAB,       frmQuery::OnSqlBookRemovePage)
 	EVT_MENU(MNU_EXPORT,            frmQuery::OnExport)
 	EVT_MENU(MNU_SAVEAS_IMAGE_GQB,     frmQuery::SaveExplainAsImage)
 	EVT_MENU(MNU_SAVEAS_IMAGE_EXPLAIN, frmQuery::SaveExplainAsImage)
@@ -170,6 +174,9 @@
 	EVT_PGQUERYRESULT(QUERY_COMPLETE, frmQuery::OnQueryComplete)
 	EVT_MENU(PGSCRIPT_COMPLETE,     frmQuery::OnScriptComplete)
 	EVT_AUINOTEBOOK_PAGE_CHANGED(CTL_NTBKCENTER, frmQuery::OnChangeNotebook)
+	// sqlQueryBook event handlers
+	EVT_AUINOTEBOOK_PAGE_CHANGED(CTL_SQLQUERYBOOK, frmQuery::OnSqlBookPageChanged)
+	EVT_AUINOTEBOOK_PAGE_CHANGING(CTL_SQLQUERYBOOK, frmQuery::OnSqlBookPageChanging)
 	EVT_SPLITTER_SASH_POS_CHANGED(GQB_HORZ_SASH, frmQuery::OnResizeHorizontally)
 	EVT_BUTTON(CTL_DELETECURRENTBTN, frmQuery::OnDeleteCurrent)
 	EVT_BUTTON(CTL_DELETEALLBTN,     frmQuery::OnDeleteAll)
@@ -235,7 +242,7 @@
 
 	loading = true;
 	closing = false;
-	origin = ORIGIN_MANUAL;
+	//origin = ORIGIN_MANUAL;
 
 	dlgName = wxT("frmQuery");
 	recentKey = wxT("RecentFiles");
@@ -263,6 +270,12 @@
 	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->Append(MNU_CLOSESQLTAB, _("&Close SQL tab"), _("Close the current query tab"));
+
 	fileMenu->AppendSeparator();
 	fileMenu->Append(MNU_EXPORT, _("&Export..."),  _("Export data to file"));
 	fileMenu->Append(MNU_QUICKREPORT, _("&Quick report..."),  _("Run a quick report..."));
@@ -495,12 +508,20 @@
 	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);
+	//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());
+
+	// 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_WINDOWLIST_BUTTON);
+	sqlQueryCounter = 0;
+	sqlQueryExec = NULL;
+
+	//boxSQL->Add(sqlQuery, 1, wxEXPAND | wxRIGHT | wxLEFT | wxBOTTOM, 1);
+	boxSQL->Add(sqlQueryBook, 1, wxEXPAND | wxRIGHT | wxLEFT | wxBOTTOM, 1);
 
 	boxQuery->Add(boxSQL, 1, wxEXPAND | wxRIGHT | wxLEFT | wxBOTTOM, 1);
 
@@ -535,8 +556,10 @@
 	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));
+	// Moved to SqlBookAddPage()
+	//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 +609,50 @@
 	// Auto indent
 	settings->Read(wxT("frmQuery/AutoIndent"), &bVal, true);
 	editMenu->Check(MNU_AUTOINDENT, bVal);
-	if (bVal)
-		sqlQuery->SetAutoIndent(true);
-	else
-		sqlQuery->SetAutoIndent(false);
+	//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);
+	//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);
+	//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);
+	//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);
+	//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,8 +667,10 @@
 		sqlQuery->SetText(query);
 		sqlQuery->Colourise(0, query.Length());
 		wxSafeYield();                            // needed to process sqlQuery modify event
-		changed = false;
-		origin = ORIGIN_INITIAL;
+		//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;
@@ -860,10 +888,11 @@
 
 	settings->WriteBool(wxT("frmQuery/AutoIndent"), editMenu->IsChecked(MNU_AUTOINDENT));
 
-	if (editMenu->IsChecked(MNU_AUTOINDENT))
-		sqlQuery->SetAutoIndent(true);
-	else
-		sqlQuery->SetAutoIndent(false);
+	SqlBookSetAutoIndent(event.IsChecked());
+	//if (editMenu->IsChecked(MNU_AUTOINDENT))
+	//	sqlQuery->SetAutoIndent(true);
+	//else
+	//	sqlQuery->SetAutoIndent(false);
 }
 
 
@@ -873,10 +902,11 @@
 
 	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());
+	//if (viewMenu->IsChecked(MNU_WORDWRAP))
+	//	sqlQuery->SetWrapMode(wxSTC_WRAP_WORD);
+	//else
+	//	sqlQuery->SetWrapMode(wxSTC_WRAP_NONE);
 }
 
 
@@ -886,10 +916,11 @@
 
 	settings->WriteBool(wxT("frmQuery/ShowIndentGuides"), viewMenu->IsChecked(MNU_SHOWINDENTGUIDES));
 
-	if (viewMenu->IsChecked(MNU_SHOWINDENTGUIDES))
-		sqlQuery->SetIndentationGuides(true);
-	else
-		sqlQuery->SetIndentationGuides(false);
+	SqlBookSetIndentGuides(event.IsChecked());
+	//if (viewMenu->IsChecked(MNU_SHOWINDENTGUIDES))
+	//	sqlQuery->SetIndentationGuides(true);
+	//else
+	//	sqlQuery->SetIndentationGuides(false);
 }
 
 
@@ -899,10 +930,11 @@
 
 	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());
+	//if (viewMenu->IsChecked(MNU_SHOWWHITESPACE))
+	//	sqlQuery->SetViewWhiteSpace(wxSTC_WS_VISIBLEALWAYS);
+	//else
+	//	sqlQuery->SetViewWhiteSpace(wxSTC_WS_INVISIBLE);
 }
 
 
@@ -912,10 +944,11 @@
 
 	settings->WriteBool(wxT("frmQuery/ShowLineEnds"), viewMenu->IsChecked(MNU_SHOWLINEENDS));
 
-	if (viewMenu->IsChecked(MNU_SHOWLINEENDS))
-		sqlQuery->SetViewEOL(1);
-	else
-		sqlQuery->SetViewEOL(0);
+	SqlBookSetViewEOL(event.IsChecked());
+	//if (viewMenu->IsChecked(MNU_SHOWLINEENDS))
+	//	sqlQuery->SetViewEOL(1);
+	//else
+	//	sqlQuery->SetViewEOL(0);
 }
 
 
@@ -925,7 +958,8 @@
 
 	settings->WriteBool(wxT("frmQuery/ShowLineNumber"), viewMenu->IsChecked(MNU_SHOWLINENUMBER));
 
-	sqlQuery->UpdateLineNumber();
+	SqlBookSetViewLineNumbers(event.IsChecked());
+	//sqlQuery->UpdateLineNumber();
 }
 
 void frmQuery::OnActivate(wxActivateEvent &event)
@@ -1080,6 +1114,7 @@
 	else
 	{
 		conn = (pgConn *)cbConnection->GetClientData(sel);
+		SqlBookSetDatabase(conn);
 		sqlResult->SetConnection(conn);
 		pgScript->SetConnection(conn);
 		title = wxT("Query - ") + cbConnection->GetValue();
@@ -1421,17 +1456,22 @@
 void frmQuery::setExtendedTitle()
 {
 	wxString chgStr;
-	if (changed)
+	//if (changed)
+	if (sqlQuery->IsChanged())
 		chgStr = wxT(" *");
 
-	if (lastPath.IsNull())
+	wxString filename = sqlQuery->GetFilename();
+	//if (lastPath.IsNull())
+	if (filename.IsNull())
 		SetTitle(title + chgStr);
 	else
 	{
-		SetTitle(title + wxT(" - [") + lastPath + wxT("]") + chgStr);
+		//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 = changed || (origin == ORIGIN_INITIAL);
+	bool enableSave = sqlQuery->IsChanged() || (sqlQuery->GetOrigin() == ORIGIN_INITIAL);
 	toolBar->EnableTool(MNU_SAVE, enableSave);
 	fileMenu->Enable(MNU_SAVE, enableSave);
 }
@@ -1668,11 +1708,14 @@
 
 bool frmQuery::CheckChanged(bool canVeto)
 {
-	if (changed && settings->GetAskSaveConfirmation())
+	//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 (!lastPath.IsNull())
+		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 +1726,14 @@
 		switch (msg.ShowModal())
 		{
 			case wxID_YES:
-				if (lastPath.IsNull())
+				//if (lastPath.IsNull())
+				if (filename.IsNull())
 					OnSaveAs(noEvent);
 				else
 					OnSave(noEvent);
 
-				return changed;
+				//return changed;
+				return sqlQuery->IsChanged();
 
 			case wxID_CANCEL:
 				return true;
@@ -1732,7 +1777,8 @@
 		return;
 	}
 
-	if (CheckChanged(event.CanVeto()) && event.CanVeto())
+	//if (CheckChanged(event.CanVeto()) && event.CanVeto())
+	if (SqlBookClose(event.CanVeto()) && event.CanVeto())
 	{
 		event.Veto();
 		return;
@@ -1749,7 +1795,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,14 +1822,18 @@
 	        // 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)))
+	        //(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)
+		//origin = ORIGIN_MANUAL;
+		sqlQuery->SetOrigin(ORIGIN_MANUAL);
+		//if (!changed)
+		if (!sqlQuery->IsChanged())
 		{
-			changed = true;
+			//changed = true;
+			sqlQuery->SetChanged(true);
 			setExtendedTitle();
 		}
 	}
@@ -1826,8 +1876,11 @@
 		sqlQuery->Colourise(0, str.Length());
 		sqlQuery->EmptyUndoBuffer();
 		wxSafeYield();                            // needed to process sqlQuery modify event
-		changed = false;
-		origin = ORIGIN_FILE;
+		//changed = false;
+		//origin = ORIGIN_FILE;
+		sqlQuery->SetFilename(lastPath);
+		sqlQuery->SetChanged(false);
+		sqlQuery->SetOrigin(ORIGIN_FILE);
 		setExtendedTitle();
 		SetLineEndingStyle();
 		UpdateRecentFiles(true);
@@ -1881,26 +1934,31 @@
 void frmQuery::OnSave(wxCommandEvent &event)
 {
 	bool modeUnicode = settings->GetUnicodeFile();
+	wxString filename = sqlQuery->GetFilename();
 
-	if (lastPath.IsNull())
+	//if (lastPath.IsNull())
+	if (filename.IsNull())
 	{
 		OnSaveAs(event);
 		return;
 	}
 
-	wxUtfFile file(lastPath, wxFile::write, modeUnicode ? wxFONTENCODING_UTF8 : wxFONTENCODING_DEFAULT);
+	//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;
+		//changed = false;
+		sqlQuery->SetChanged(false);
 		setExtendedTitle();
 		UpdateRecentFiles();
 	}
 	else
 	{
-		wxLogError(__("Could not write the file %s: Errcode=%d."), lastPath.c_str(), wxSysErrorCode());
+		//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 +1982,8 @@
 	{
 		wxMessageBox(_("This file contains mixed line endings. They will be converted to the current setting."), _("Warning"), wxICON_INFORMATION | wxOK);
 		sqlQuery->ConvertEOLs(mode);
-		changed = true;
+		//changed = true;
+		sqlQuery->SetChanged(true);
 		setExtendedTitle();
 		updateMenu();
 	}
@@ -1940,27 +1999,28 @@
 
 	// 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!!"));
-	}
+//	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 +2052,16 @@
 
 	SetEOLModeDisplay(mode);
 
-	if (!changed)
+	//if (!changed)
+	if (!sqlQuery->IsChanged())
 	{
-		changed = true;
+		//changed = true;
+		sqlQuery->SetChanged(true);
 		setExtendedTitle();
 	}
+	setExtendedTitle();
 
+	// TODO: ??
 	pgScript->SetConnection(conn);
 }
 
@@ -2031,11 +2095,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,12 +2138,16 @@
 			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;
+			//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 (origin == ORIGIN_INITIAL)
+			//	origin = ORIGIN_FILE;
+			if (sqlQuery->GetOrigin() == ORIGIN_INITIAL)
+				sqlQuery->SetOrigin(ORIGIN_FILE);
 
 			setExtendedTitle();
 			UpdateRecentFiles();
@@ -2257,7 +2330,8 @@
 
 	// 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(changed && origin != ORIGIN_GQB &&
+	if (sqlQuery->IsChanged() && sqlQuery->GetOrigin() != ORIGIN_GQB &&
 	        !sqlQuery->GetText().Trim().IsEmpty() && sqlQuery->GetText() != newQuery + wxT("\n"))
 	{
 		wxString fn;
@@ -2267,7 +2341,8 @@
 			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 && changed)
+		if(msg.ShowModal() == wxID_YES && sqlQuery->IsChanged())
 		{
 			canGenerate = true;
 		}
@@ -2287,8 +2362,10 @@
 		sqlQuery->Colourise(0, sqlQuery->GetText().Length());
 		wxSafeYield();                            // needed to process sqlQuery modify event
 		sqlNotebook->SetSelection(0);
-		changed = true;
-		origin = ORIGIN_GQB;
+		//changed = true;
+		//origin = ORIGIN_GQB;
+		sqlQuery->SetChanged(true);
+		sqlQuery->SetOrigin(ORIGIN_GQB);
 		setExtendedTitle();
 
 		gqbUpdateRunning = false;
@@ -2437,6 +2514,7 @@
 		}
 		query.Replace(wxT("$SELECTION$"), selection);
 	}
+
 	execQuery(query);
 	sqlQuery->SetFocus();
 }
@@ -2495,7 +2573,8 @@
 	sqlQuery->StartStyling(0, wxSTC_INDICS_MASK);
 	sqlQuery->SetStyling(sqlQuery->GetText().Length(), 0);
 
-	if (!changed)
+	//if (!changed)
+	if (!sqlQuery->IsChanged())
 		setExtendedTitle();
 
 	aborted = false;
@@ -2519,6 +2598,9 @@
 		}
 	}
 
+	// Remember the tab from which execute was called. By the time query completes, SQL tab selection may change.
+	sqlQueryExec = sqlQuery;
+
 	// We must do this lot before the query starts, otherwise
 	// it might not happen once the main thread gets busy with
 	// other stuff.
@@ -2852,9 +2934,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 +2944,30 @@
 
 				// 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 (!changed)
+					if (!sqlQueryExec->IsChanged())
 						setExtendedTitle();
 
-					sqlQuery->EnsureVisible(line);
+					sqlQueryExec->EnsureVisible(line);
 				}
 			}
 		}
@@ -2981,9 +3064,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,6 +3259,7 @@
 		updateMenu();
 	}
 
+	sqlQueryExec = NULL;
 	sqlQuery->SetFocus();
 }
 
@@ -3478,8 +3562,10 @@
 		sqlQuery->SetText(query);
 		sqlQuery->Colourise(0, query.Length());
 		wxSafeYield();                            // needed to process sqlQuery modify event
-		changed = true;
-		origin = ORIGIN_HISTORY;
+		//changed = true;
+		//origin = ORIGIN_HISTORY;
+		sqlQuery->SetChanged(true);
+		sqlQuery->SetOrigin(ORIGIN_HISTORY);
 		setExtendedTitle();
 		SetLineEndingStyle();
 		btnDeleteCurrent->Enable(true);
@@ -3523,6 +3609,233 @@
 	}
 }
 
+// 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();
+		// Maybe status bar?
+		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::OnSqlBookRemovePage(wxCommandEvent &event)
+{
+	// Don't allow removal of the last SQL box via user generated event
+	size_t pagecnt = sqlQueryBook->GetPageCount();
+	if (pagecnt == 1)
+	{
+		wxMessageBox(_("Cannot remove the last SQL tab"));
+		return;
+	}
+
+	// Prevent removing the page that is currently being executed
+	if (sqlQueryExec != NULL && sqlQueryExec == sqlQuery)
+	{
+		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))
+		return;
+
+	if (!SqlBookRemovePage())
+		wxMessageBox(_("Could not close selected tab"));
+}
+
+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 = _("Query") + wxString::Format(wxT(" %i"), sqlQueryCounter);
+	sqlQueryBook->AddPage(box, caption, true);
+
+	// Probably not needed, as the line above should trigger the PageChange event
+	sqlQuery = box;
+}
+
+bool frmQuery::SqlBookRemovePage()
+{
+	size_t pageidx;
+	if (sqlQueryBook->GetPageCount() > 0)
+	{
+		sqlQuery->Disconnect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus));
+		sqlQuery->Disconnect(wxID_ANY, wxEVT_KILL_FOCUS, wxFocusEventHandler(frmQuery::OnFocus));
+
+		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);
+	}
+}
+
+// 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-01 08:18:21.538647362 -0600
@@ -74,6 +74,14 @@
 
 	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();
+
 	DECLARE_DYNAMIC_CLASS(ctlSQLBox)
 	DECLARE_EVENT_TABLE()
 
@@ -93,6 +101,11 @@
 	pgConn *m_database;
 	bool m_autoIndent, m_autocompDisabled;
 
+	// Variables to track info per SQL box
+	wxString m_filename;
+	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-01 19:13:00.098158513 -0600
@@ -101,11 +101,13 @@
 	}
 	void SetChanged(bool p_changed)
 	{
-		changed = p_changed;
+		//changed = p_changed;
+		sqlQuery->SetChanged(p_changed);
 	}
 	void SetOrigin(int p_origin)
 	{
-		origin = p_origin;
+		//origin = p_origin;
+		sqlQuery->SetOrigin(p_origin);
 	}
 	void SetLastPath(wxString p_lastpath)
 	{
@@ -135,6 +137,10 @@
 	wxButton *btnDeleteAll;
 	wxArrayString histoQueries;
 
+	ctlAuiNotebook *sqlQueryBook;
+	size_t sqlQueryCounter;
+	ctlSQLBox *sqlQueryExec; //currently executing SQL tab
+
 	// Query timing/status update
 	wxTimer timer;
 	wxLongLong elapsedQuery, startTimeQuery;
@@ -261,6 +267,24 @@
 
 	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);
+	bool SqlBookClose(bool canVeto);
+	// SQL tabs event handlers
+	void OnSqlBookAddPage(wxCommandEvent &event);
+	void OnSqlBookRemovePage(wxCommandEvent &event);
+	void OnSqlBookPageChanged(wxAuiNotebookEvent &event);
+	void OnSqlBookPageChanging(wxAuiNotebookEvent &event);
+
 	wxWindow *currentControl();
 	wxMenu *queryMenu;
 	wxMenu *favouritesMenu;
@@ -280,7 +304,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-01 08:20:54.148645460 -0600
@@ -44,6 +44,8 @@
 	MNU_OPEN,
 	MNU_SAVE,
 	MNU_SAVEAS,
+	MNU_NEWSQLTAB,
+	MNU_CLOSESQLTAB,
 	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

Reply via email to