pgadmin3/utils/misc.cpp

1539 lines
32 KiB
C++

//////////////////////////////////////////////////////////////////////////
//
// pgAdmin III - PostgreSQL Tools
//
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
// misc.cpp - Miscellaneous Utilities
//
//////////////////////////////////////////////////////////////////////////
#include "pgAdmin3.h"
// wxWindows headers
#include <wx/wx.h>
#include <wx/app.h>
#include <wx/timer.h>
#include <wx/xrc/xmlres.h>
#include <wx/dir.h>
#include <wx/file.h>
#include <wx/textbuf.h>
#include <wx/help.h>
#include <wx/html/helpctrl.h>
#include <wx/fontenc.h>
#include <wx/display.h>
#include "utils/utffile.h"
#include <locale.h>
#ifdef __WXMSW__
#include <wx/msw/helpchm.h>
#endif
// Standard headers
#include <stdlib.h>
// App headers
#include "utils/misc.h"
#if !defined(PGSCLI)
// App headers
#include "frm/frmMain.h"
wxImageList *imageList = 0;
#endif // PGSCLI
extern "C"
{
#define YYSTYPE_IS_DECLARED
#define DECIMAL DECIMAL_P
typedef int YYSTYPE;
#include "parser/keywords.h"
}
// we dont have an appropriate wxLongLong method
#ifdef __WIN32__
#define atolonglong _atoi64
#else
#ifdef __WXMAC__
#define atolonglong(str) strtoll(str, (char **)NULL, 10)
#else
#ifdef __FreeBSD__
#define atolonglong(str) strtoll(str, (char **)NULL, 10)
#else
#define atolonglong atoll
#endif
#endif
#endif
// Conversions
wxString BoolToYesNo(bool value)
{
return value ? _("Yes") : _("No");
}
wxString BoolToStr(bool value)
{
return value ? wxT("true") : wxT("false");
}
wxString escapeHtml(wxString text, bool pre) {
text.Replace("&", "&amp;");
text.Replace("<", "&lt;");
text.Replace(">", "&gt;");
if (!pre) text.Replace("\n", "&para;<br>");
return text;
}
bool StrToBool(const wxString &value)
{
if (value.StartsWith(wxT("t")))
{
return true;
}
else if (value.StartsWith(wxT("T")))
{
return true;
}
else if (value.StartsWith(wxT("1")))
{
return true;
}
else if (value.StartsWith(wxT("Y")))
{
return true;
}
else if (value.StartsWith(wxT("y")))
{
return true;
}
else if (value == wxT("on"))
return true;
return false;
}
wxString NumToStr(long value)
{
wxString result;
result.Printf(wxT("%ld"), value);
return result;
}
wxString NumToStr(long long value)
{
wxString result;
result.Printf(wxT("%lld"), value);
return result;
}
wxString NumToStr(OID value)
{
wxString result;
result.Printf(wxT("%lu"), (long)value);
return result;
}
long StrToLong(const wxString &value)
{
return atol(value.ToAscii());
}
long long StrTolonglong(const wxString &value)
{
return atoll(value.ToAscii());
}
OID StrToOid(const wxString &value)
{
return (OID)strtoul(value.ToAscii(), 0, 10);
}
wxString generate_spaces(int length)
{
return wxString().Pad(length);
}
wxString NumToStr(double value)
{
wxString result;
static wxString decsep;
if (decsep.Length() == 0)
{
decsep.Printf(wxT("%lf"), 1.2);
decsep = decsep[(unsigned int)1];
}
result.Printf(wxT("%lf"), value);
result.Replace(decsep, wxT("."));
// Get rid of excessive decimal places
if (result.Contains(wxT(".")))
while (result.Right(1) == wxT("0"))
result.RemoveLast();
if (result.Right(1) == wxT("."))
result.RemoveLast();
return result;
}
wxString NumToStrHuman(wxLongLong value) {
// billion
long ddiv = 1000000000;
wxLongLong r = 0;
wxString s;
while ((r=value/ddiv)==0) {
ddiv = ddiv / 1000;
if (ddiv == 0) return wxEmptyString;
}
if (ddiv == 1000000000) s = _("Bi");
else if (ddiv == 1000000) s = _("Mi");
else if (ddiv == 1000) s = _("ths");
else return wxEmptyString;
wxLongLong m = value % ddiv;
m = m / (ddiv / 10);
wxString rez;
rez = NumToStr(r) + (m == 0 ? "": "." + NumToStr(m))+" "+s;
return rez;
}
wxString NumToStr(wxLongLong value)
{
wxString str;
#if wxCHECK_VERSION(2, 9, 0)
str.Printf("%" wxLongLongFmtSpec "d", value.GetValue());
#else
str.Printf(wxT("%") wxLongLongFmtSpec wxT("d"), value.GetValue());
#endif
return str;
}
double StrToDouble(const wxString &value)
{
wxCharBuffer buf = value.ToAscii();
char *p = (char *)strchr(buf, '.');
if (p)
*p = localeconv()->decimal_point[0];
return strtod(buf, 0);
}
wxLongLong StrToLongLong(const wxString &value)
{
return atolonglong(value.ToAscii());
}
wxString DateToAnsiStr(const wxDateTime &datetime)
{
if (!datetime.IsValid())
return wxEmptyString;
return datetime.FormatISODate() + wxT(" ") + datetime.FormatISOTime();
}
wxString DateToStr(const wxDateTime &datetime)
{
if (!datetime.IsValid())
return wxEmptyString;
return datetime.FormatDate() + wxT(" ") + datetime.FormatTime();
}
wxString ContrastColorBlackOrWhite(wxColour &bgColor) {
float k = bgColor.GetRed() * 0.299 + bgColor.GetGreen() * 0.587 + bgColor.GetBlue() * 0.114;
if (k <= 150) return "#FFFFFF"; else return "#000000";
}
/// <summary>
///
/// </summary>
/// <param name="sourcestringsize"> NN MB , N bytes, N kB, N GB</param>
/// <returns> size MB</returns>
double ConvertSizeToMB(const wxString& sourcestringsize) {
double d = 0;
if (sourcestringsize.ToCDouble(&d)) {
d = 0;
}
else {
if (sourcestringsize.Right(2) == "kB") d = d / 1024; //kB => MB
else if (sourcestringsize.Right(2) == "GB") d = d * 1024;//GB => MB
else if (sourcestringsize.Right(2) == "TB") d = d * 1024 * 1024;//TB => MB
else if (sourcestringsize.Right(5) == "bytes") d = d / 1024 / 1024; //bytes => MB
}
return d;
}
wxString ElapsedTimeToStr(wxLongLong msec)
{
wxTimeSpan tsMsec(0, 0, 0, msec);
int days = tsMsec.GetDays();
int hours = (wxTimeSpan(tsMsec.GetHours(), 0, 0, 0) - wxTimeSpan(days * 24)).GetHours();
int minutes = (wxTimeSpan(0, tsMsec.GetMinutes(), 0, 0) - wxTimeSpan(hours)).GetMinutes();
long seconds = (wxTimeSpan(0, 0, tsMsec.GetSeconds(), 0) - wxTimeSpan(hours, minutes)).GetSeconds().ToLong();
long milliseconds = (wxTimeSpan(0, 0, 0, tsMsec.GetMilliseconds()) - wxTimeSpan(0, 0, seconds)).GetMilliseconds().ToLong();
if (days > 0)
return wxString::Format(
wxT("%d %s, %02d:%02d:%02ld hours"),
days, wxT("days"), hours, minutes, seconds
);
else if (hours > 0)
return wxString::Format(
wxT("%02d:%02d:%02ld hours"), hours, minutes, seconds
);
else if (msec >= 1000 * 60)
return wxString::Format(wxT("%02d:%02ld minutes"), minutes, seconds);
else if (msec >= 1000)
return wxString::Format(
wxT("%ld.%ld secs"), seconds, milliseconds / 100
);
else
return msec.ToString() + wxT(" msec");
}
wxDateTime StrToDateTime(const wxString &value)
{
wxDateTime dt;
/* This hasn't just been used. ( Is not infinity ) */
if ( !value.IsEmpty() )
dt.ParseDateTime(value);
return dt;
}
#if !defined(PGSCLI)
void CheckOnScreen(wxWindow *win, wxPoint &pos, wxSize &size, const int w0, const int h0)
{
wxRect rect;
int scrH, scrW;
wxSize screenSize = wxGetDisplaySize();
scrW = screenSize.x;
scrH = screenSize.y;
if (pos.x > scrW - w0)
pos.x = scrW - w0;
if (pos.y > scrH - h0)
pos.y = scrH - h0;
if (pos.x < 0)
pos.x = 0;
if (pos.y < 0)
pos.y = 0;
if (size.GetWidth() < w0)
size.SetWidth(w0);
if (size.GetHeight() < h0)
size.SetHeight(h0);
if (size.GetWidth() > scrW)
size.SetWidth(scrW);
if (size.GetHeight() > scrH)
size.SetHeight(scrH);
}
#endif // PGSCLI
wxString qtConnString(const wxString &value)
{
wxString result = value;
result.Replace(wxT("\\"), wxT("\\\\"));
result.Replace(wxT("'"), wxT("\\'"));
result.Append(wxT("'"));
result.Prepend(wxT("'"));
return result;
}
#if !defined(PGSCLI)
wxString IdAndName(long id, const wxString &name)
{
wxString str;
str.Printf(wxT("%ld - %s"), id, name.BeforeFirst('\n').c_str());
return str;
}
wxString qtDbStringDollar(const wxString &value)
{
wxString qtDefault = wxT("BODY");
wxString qt = qtDefault;
int counter = 1;
if (value.Find('\'') < 0 && value.Find('\n') < 0 && value.Find('\r') < 0)
{
wxString ret = value;
ret.Replace(wxT("\\"), wxT("\\\\"));
ret.Replace(wxT("'"), wxT("''"));
ret.Append(wxT("'"));
ret.Prepend(wxT("'"));
return ret;
}
while (value.Find(wxT("$") + qt + wxT("$")) >= 0)
qt.Printf(wxT("%s%d"), qtDefault.c_str(), counter++);
return wxT("$") + qt + wxT("$")
+ value
+ wxT("$") + qt + wxT("$");
}
void FillKeywords(wxString &str)
{
// unfortunately, the keyword list is static.
int i;
str = wxString();
for (i = 0; i < NumScanKeywords; i++)
{
str += wxT(" ") + wxString::FromAscii(ScanKeywords[i].name);
}
for (i = 0; i < NumScanKeywordsExtra; i++)
{
str += wxT(" ") + wxString::FromAscii(ScanKeywordsExtra[i].name);
}
}
#endif // PGSCLI
static bool needsQuoting(wxString &value, bool forTypes)
{
// Is it a number?
if (value.IsNumber())
return true;
else
{
// certain types should not be quoted even though it contains a space. Evilness.
wxString valNoArray;
if (forTypes && value.Right(2) == wxT("[]"))
valNoArray = value.Mid(0, value.Len() - 2);
else
valNoArray = value;
if (forTypes &&
(!valNoArray.CmpNoCase(wxT("character varying")) ||
!valNoArray.CmpNoCase(wxT("\"char\"")) ||
!valNoArray.CmpNoCase(wxT("bit varying")) ||
!valNoArray.CmpNoCase(wxT("double precision")) ||
!valNoArray.CmpNoCase(wxT("timestamp without time zone")) ||
!valNoArray.CmpNoCase(wxT("timestamp with time zone")) ||
!valNoArray.CmpNoCase(wxT("time without time zone")) ||
!valNoArray.CmpNoCase(wxT("time with time zone")) ||
!valNoArray.CmpNoCase(wxT("\"trigger\"")) ||
!valNoArray.CmpNoCase(wxT("\"unknown\""))))
return false;
int pos = 0;
while (pos < (int)valNoArray.length())
{
wxChar c = valNoArray.GetChar(pos);
if (!((pos > 0) && (c >= '0' && c <= '9')) &&
!(c >= 'a' && c <= 'z') &&
!(c == '_'))
{
return true;
}
pos++;
}
}
// is it a keyword?
const ScanKeyword *sk = ScanKeywordLookup(value.ToAscii());
if (!sk)
return false;
if (sk->category == UNRESERVED_KEYWORD)
return false;
if (forTypes && sk->category == COL_NAME_KEYWORD)
return false;
return true;
}
wxString qtTypeIdent(const wxString &value)
{
if (value.Length() == 0)
return value;
wxString result = value;
if (needsQuoting(result, true))
{
result.Replace(wxT("\""), wxT("\"\""));
return wxT("\"") + result + wxT("\"");
}
else
return result;
}
wxString qtIdent(const wxString &value)
{
if (value.Length() == 0)
return value;
wxString result = value;
if (needsQuoting(result, false))
{
result.Replace(wxT("\""), wxT("\"\""));
return wxT("\"") + result + wxT("\"");
}
else
return result;
}
#if !defined(PGSCLI)
wxString qtStrip(const wxString &str)
{
if (str.Left(2) == wxT("\\\""))
return str.Mid(2, str.Length() - 4);
else
return str;
}
wxString TransformToNewDatconfig(const wxString &list)
{
const wxChar *cp = list.c_str();
wxString config = wxEmptyString;
wxString str = wxEmptyString;
bool quote = false;
while (*cp)
{
switch (*cp)
{
case '\\':
{
if (cp[1] == '"')
{
str.Append(*cp);
cp++;
str.Append(*cp);
}
break;
}
case '"':
case '\'':
{
quote = !quote;
str.Append(*cp);
break;
}
case ',':
{
if (!quote)
{
if (!config.IsEmpty())
config += wxT(",");
config += wxT("=") + str;
str = wxEmptyString;
break;
}
}
default:
{
str.Append(*cp);
break;
}
}
cp++;
}
if (!str.IsEmpty())
{
if (!config.IsEmpty())
config += wxT(",");
config += wxT("=") + str;
}
return config;
}
void FillArray(wxArrayString &array, const wxString &list)
{
const wxChar *cp = list.c_str();
wxString str;
bool quote = false;
while (*cp)
{
switch (*cp)
{
case '\\':
{
if (cp[1] == '"')
{
cp++;
str.Append(*cp);
}
break;
}
case '"':
case '\'':
{
quote = !quote;
break;
}
case ',':
{
if (!quote)
{
array.Add(str);
str = wxEmptyString;
break;
}
}
default:
{
str.Append(*cp);
break;
}
}
cp++;
}
if (!str.IsEmpty())
array.Add(str);
}
queryTokenizer::queryTokenizer(const wxString &str, const wxChar delim)
: wxStringTokenizer()
{
if (delim == (wxChar)' ')
SetString(str, wxT(" \n\r\t"), wxTOKEN_RET_EMPTY_ALL);
else
SetString(str, delim, wxTOKEN_RET_EMPTY_ALL);
delimiter = delim;
}
void AppendIfFilled(wxString &str, const wxString &delimiter, const wxString &what)
{
if (!what.IsNull())
str += delimiter + what;
}
wxString queryTokenizer::GetNextToken()
{
// we need to override wxStringTokenizer, because we have to handle quotes
wxString str;
bool foundQuote = false;
do
{
wxString s = wxStringTokenizer::GetNextToken();
str.Append(s);
int quotePos;
do
{
quotePos = s.Find('"');
if (quotePos >= 0)
{
foundQuote = !foundQuote;
s = s.Mid(quotePos + 1);
}
}
while (quotePos >= 0);
if (foundQuote)
str.Append(delimiter);
}
while (foundQuote && HasMoreTokens());
return str;
}
wxString FileRead(const wxString &filename, int format)
{
wxString str;
wxFontEncoding encoding;
if (format > 0)
encoding = wxFONTENCODING_UTF8;
else
encoding = wxFONTENCODING_DEFAULT;
wxUtfFile file(filename, wxFile::read, encoding);
if (file.IsOpened())
file.Read(str);
return wxTextBuffer::Translate(str, wxTextFileType_Unix); // we want only \n
}
bool FileWrite(const wxString &filename, const wxString &data, int format)
{
wxFontEncoding encoding = wxFONTENCODING_DEFAULT;
wxUtfFile file;
if (format < 0)
{
if (wxFile::Access(filename, wxFile::read))
{
file.Open(filename);
encoding = file.GetEncoding();
file.Close();
}
if (encoding == wxFONTENCODING_DEFAULT)
encoding = settings->GetUnicodeFile() ? wxFONTENCODING_UTF8 : wxFONTENCODING_SYSTEM;
}
else
encoding = format ? wxFONTENCODING_UTF8 : wxFONTENCODING_SYSTEM;
file.Open(filename, wxFile::write, wxS_DEFAULT, encoding);
if (file.IsOpened())
return file.Write(wxTextBuffer::Translate(data));
return false;
}
wxString CleanHelpPath(const wxString &path)
{
wxString thePath = path;
if (thePath.IsEmpty())
return wxEmptyString;
// If the filename ends in .chm, .hhp, .pdf or .zip, it's
// a file based help system and we can assumes it's
// correct.
if (thePath.Lower().EndsWith(wxT(".hhp")) ||
#if defined (__WXMSW__) || wxUSE_LIBMSPACK
thePath.Lower().EndsWith(wxT(".chm")) ||
#endif
thePath.Lower().EndsWith(wxT(".pdf")) ||
thePath.Lower().EndsWith(wxT(".zip")))
return thePath;
// In all other cases we must have a directory
wxString sep;
// Figure out the appropriate seperator
if (thePath.Lower().Contains(wxT("://")))
sep = wxT("/");
else
sep = wxFileName::GetPathSeparator();
// First, correct the path separators
thePath.Replace(wxT("/"), sep);
thePath.Replace(wxT("\\"), sep);
// Now, append the seperator if it's not there
if (!thePath.EndsWith(sep))
thePath += sep;
return thePath;
}
bool HelpPathValid(const wxString &path)
{
if (path.IsEmpty())
return true;
// If the filename contains any of the sensible URL schemes
// we just assume it's correct if the end also looks right.
if ((path.Lower().StartsWith(wxT("http://")) ||
path.Lower().StartsWith(wxT("https://")) ||
path.Lower().StartsWith(wxT("file://")) ||
path.Lower().StartsWith(wxT("ftp://"))) &&
(path.Lower().EndsWith(wxT(".hhp")) ||
#if defined (__WXMSW__) || wxUSE_LIBMSPACK
path.Lower().EndsWith(wxT(".chm")) ||
#endif
path.Lower().EndsWith(wxT(".pdf")) ||
path.Lower().EndsWith(wxT(".zip")) ||
path.Lower().EndsWith(wxT("/"))))
return true;
// Otherwise, we're looking for a file (or directory) that
// actually exists.
wxString sep = wxFileName::GetPathSeparator();
if (path.Lower().EndsWith(wxT(".hhp")) ||
#if defined (__WXMSW__) || wxUSE_LIBMSPACK
path.Lower().EndsWith(wxT(".chm")) ||
#endif
path.Lower().EndsWith(wxT(".pdf")) ||
path.Lower().EndsWith(wxT(".zip")))
return wxFile::Exists(path);
else if (path.Lower().EndsWith(sep))
return wxDir::Exists(path);
else
return false;
}
void DisplayHelp(const wxString &helpTopic, const HelpType helpType)
{
static wxHelpControllerBase *pgHelpCtl = 0;
static wxHelpControllerBase *edbHelpCtl = 0;
static wxHelpControllerBase *greenplumHelpCtl = 0;
static wxHelpControllerBase *slonyHelpCtl = 0;
static wxString pgInitPath = wxEmptyString;
static wxString edbInitPath = wxEmptyString;
static wxString gpInitPath = wxEmptyString;
static wxString slonyInitPath = wxEmptyString;
switch (helpType)
{
case HELP_PGADMIN:
DisplayPgAdminHelp(helpTopic);
break;
case HELP_POSTGRESQL:
DisplayExternalHelp(helpTopic, settings->GetPgHelpPath(), pgHelpCtl, (pgInitPath != settings->GetPgHelpPath() ? true : false));
pgInitPath = settings->GetPgHelpPath();
break;
case HELP_ENTERPRISEDB:
DisplayExternalHelp(helpTopic, settings->GetEdbHelpPath(), edbHelpCtl, (edbInitPath != settings->GetEdbHelpPath() ? true : false));
edbInitPath = settings->GetEdbHelpPath();
break;
case HELP_GREENPLUM:
{
// the old help path (stored in the settings) is no longer working
static wxString gpHelpPath = settings->GetGpHelpPath();
// Note: never end the URL on "index.html"
// InitHelp() does obscure magic with this ending
if (gpHelpPath.CmpNoCase(wxT("http://docs.gopivotal.com/gpdb/")) == 0)
{
gpHelpPath = wxT("http://gpdb.docs.pivotal.io/");
// Replace the path to the old domain with the link to
// the new documentation path
// The old link is working for now, but there is no guarantee
// that it will stay this way
// Also the new link automatically redirects to the latest version
settings->SetGpHelpPath(gpHelpPath);
}
if (gpHelpPath.CmpNoCase(wxT("http://www.greenplum.com/docs/3300/")) == 0)
{
gpHelpPath = wxT("http://gpdb.docs.pivotal.io/");
// this is the old link, update the link to the new documentation link
// problem: this saves the link into the configuration file
settings->SetGpHelpPath(gpHelpPath);
}
DisplayExternalHelp(helpTopic, settings->GetGpHelpPath(), greenplumHelpCtl, (gpInitPath != settings->GetGpHelpPath() ? true : false));
gpInitPath = settings->GetGpHelpPath();
}
break;
case HELP_SLONY:
DisplayExternalHelp(helpTopic, settings->GetSlonyHelpPath(), slonyHelpCtl, (slonyInitPath != settings->GetSlonyHelpPath() ? true : false));
slonyInitPath = settings->GetSlonyHelpPath();
break;
default:
DisplayPgAdminHelp(helpTopic);
break;
}
}
void DisplayPgAdminHelp(const wxString &helpTopic)
{
static wxHelpControllerBase *helpCtl = 0;
static bool firstCall = true;
// Startup the main help system
if (firstCall)
{
firstCall = false;
wxString helpdir = docPath + wxT("/") + settings->GetCanonicalLanguageName();
if (!wxFile::Exists(helpdir + wxT("/pgadmin3.hhp")) &&
#if defined(__WXMSW__) || wxUSE_LIBMSPACK
!wxFile::Exists(helpdir + wxT("/pgadmin3.chm")) &&
#endif
!wxFile::Exists(helpdir + wxT("/pgadmin3.zip")))
helpdir = docPath + wxT("/en_US");
#ifdef __WXMSW__
#ifndef __WXDEBUG__
if (wxFile::Exists(helpdir + wxT("/pgadmin3.chm")))
{
helpCtl = new wxCHMHelpController();
helpCtl->Initialize(helpdir + wxT("/pgadmin3"));
}
else
#endif
#endif
#if wxUSE_LIBMSPACK
if (wxFile::Exists(helpdir + wxT("/pgadmin3.chm")) ||
wxFile::Exists(helpdir + wxT("/pgadmin3.hhp")) || wxFile::Exists(helpdir + wxT("/pgadmin3.zip")))
#else
if (wxFile::Exists(helpdir + wxT("/pgadmin3.hhp")) || wxFile::Exists(helpdir + wxT("/pgadmin3.zip")))
#endif
{
helpCtl = new wxHtmlHelpController();
helpCtl->Initialize(helpdir + wxT("/pgadmin3"));
}
}
wxString page;
int hashPos = helpTopic.Find('#');
if (hashPos < 0)
page = helpTopic + wxT(".html");
else
page = helpTopic.Left(hashPos) + wxT(".html") + helpTopic.Mid(hashPos);
if (helpCtl)
{
if (helpTopic == wxT("index.html"))
helpCtl->DisplayContents();
else
helpCtl->DisplaySection(page);
}
else
{
wxLaunchDefaultBrowser(page);
}
}
void DisplayExternalHelp(const wxString &helpTopic, const wxString &docPath, wxHelpControllerBase *helpCtl, const bool init)
{
// Build the page name
wxString page;
int hashPos = helpTopic.Find('#');
if (hashPos < 0)
page = helpTopic + wxT(".html");
else
page = helpTopic.Left(hashPos) + wxT(".html") + helpTopic.Mid(hashPos);
// If the docPath ends in .pdf, then open the file in the browser. No
// bookmarks though :-(
if (docPath.Lower().EndsWith(wxT(".pdf")))
{
wxLaunchDefaultBrowser(docPath);
return;
}
// If the docPath doesn't end in .chm, .zip or .hhp, then we must be using
// plain HTML files, so just fire off the browser and be done with it.
if (!docPath.Lower().EndsWith(wxT(".hhp")) &&
#if defined (__WXMSW__) || wxUSE_LIBMSPACK
!docPath.Lower().EndsWith(wxT(".chm")) &&
#endif
!docPath.Lower().EndsWith(wxT(".zip")))
{
wxLaunchDefaultBrowser(docPath + page);
return;
}
// We must be using HTML Help, so init the appropriate help controller
// Note the path that we init for - if it changes, we need to init a
// new controller in case it's no longer the same type
if (init || !helpCtl)
{
// Get shot of the old help controller if there is one.
if (helpCtl)
delete helpCtl;
#ifdef __WXMSW__
// For Windows builds we us the MS HTML Help viewer for .chm files
if (docPath.Lower().EndsWith(wxT(".chm")) && wxFile::Exists(docPath))
{
helpCtl = new wxCHMHelpController();
helpCtl->Initialize(docPath);
}
else
#endif
#if wxUSE_LIBMSPACK
// If we can use a .chm file...
if ((docPath.Lower().EndsWith(wxT(".chm")) && wxFile::Exists(docPath)) ||
(docPath.Lower().EndsWith(wxT(".hhp")) && wxFile::Exists(docPath)) ||
(docPath.Lower().EndsWith(wxT(".zip")) && wxFile::Exists(docPath)))
#else
// Otherwise...
if ((docPath.Lower().EndsWith(wxT(".hhp")) && wxFile::Exists(docPath)) ||
(docPath.Lower().EndsWith(wxT(".zip")) && wxFile::Exists(docPath)))
#endif
{
helpCtl = new wxHtmlHelpController();
helpCtl->Initialize(docPath);
}
}
// Display the page using the help controller
// If it's foobar'ed, use the browser.
if (helpCtl)
{
if (helpTopic == wxT("index.html"))
helpCtl->DisplayContents();
else
helpCtl->DisplaySection(page);
}
else
{
wxLogError(_("The help source (\"%s\") could not be opened. Please check the help configuration options."), docPath.c_str());
}
}
wxString GetHtmlEntity(const wxChar ch)
{
// REWRITE THIS - IT'S (STILL) BLOODY INEFFICIENT!!
// Quick bailout
if ((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9'))
return wxString(ch);
unsigned short ents[] =
{
34,
39,
38,
60,
62,
160,
161,
164,
162,
163,
165,
166,
167,
168,
169,
170,
171,
172,
173,
174,
8482,
175,
176,
177,
178,
179,
180,
181,
182,
183,
184,
185,
186,
187,
188,
189,
190,
191,
215,
247,
192,
193,
194,
195,
196,
197,
198,
199,
200,
201,
202,
203,
204,
205,
206,
207,
208,
209,
210,
211,
212,
213,
214,
216,
217,
218,
219,
220,
221,
222,
223,
224,
225,
226,
227,
228,
229,
230,
231,
232,
233,
234,
235,
236,
237,
238,
239,
240,
241,
242,
243,
244,
245,
246,
248,
249,
250,
251,
252,
253,
254,
255,
338,
339,
352,
353,
376,
710,
732,
8194,
8195,
8201,
8204,
8205,
8206,
8207,
8211,
8212,
8216,
8217,
8218,
8220,
8221,
8222,
8224,
8225,
8230,
8240,
8249,
8250,
8364,
0
};
int elem = 0;
while (ents[elem] != 0)
{
if (ch == ents[elem])
{
wxString ret = wxT("&#");
ret += NumToStr((long)ents[elem]);
ret += wxT(";");
return ret;
}
elem++;
}
return wxString(ch);
}
wxString HtmlEntities(const wxString &str)
{
wxString ret;
for (unsigned int x = 0; x < str.Length(); x++)
{
if (str[x] != 13)
ret += GetHtmlEntity(str[x]);
}
return ret;
}
#ifndef WIN32
wxString ExecProcess(const wxString &cmd)
{
wxString res;
FILE *f = popen(cmd.ToAscii(), "r");
if (f)
{
char buffer[1024];
int cnt;
while ((cnt = fread(buffer, 1, 1024, f)) > 0)
{
res += wxString::FromAscii(buffer);
}
pclose(f);
}
return res;
}
int ExecProcess(const wxString &command, wxArrayString &result)
{
FILE *fp_command;
char buf[4098];
fp_command = popen(command.mb_str(wxConvUTF8), "r");
if (!fp_command)
return -1;
while(!feof(fp_command))
{
if (fgets(buf, 4096, fp_command) != NULL)
result.Add(wxString::FromAscii(buf));
}
return pclose(fp_command);
}
#endif
#ifdef WIN32
#if (_MSC_VER < 1300)
/* _ftol2 is more than VC7. */
/*
extern "C" long _ftol( double );
extern "C" long _ftol2( double dblSource )
{
return _ftol( dblSource );
}
*/
#endif
#endif
wxString firstLineOnly(const wxString &str)
{
wxString ip, tmp;
ip = str;
ip = ip.Trim(true).Trim(false);
if (ip.Contains(wxT("\r\n")) && (ip.First(wxT("\r")) < ip.First(wxT("\n"))))
{
tmp = ip.BeforeFirst('\r');
if (ip.BeforeFirst('\r').Length() != ip.Length())
tmp += wxT("...");
}
else
{
tmp = ip.BeforeFirst('\n');
if (ip.BeforeFirst('\n').Length() != ip.Length())
tmp += wxT("...");
}
return tmp;
}
bool pgAppMinimumVersion(const wxString &cmd, const int majorVer, const int minorVer)
{
wxArrayString output;
bool isEnterpriseDB = false;
#ifdef __WXMSW__
if (wxExecute(cmd + wxT(" --version"), output, 0) != 0)
#else
if (ExecProcess(cmd + wxT(" --version"), output) != 0)
#endif
{
wxLogError(_("Failed to execute: %s --version"), cmd.c_str());
return false;
}
// Is this an EDB utility?
if (output[0].Contains(wxT("EnterpriseDB")))
isEnterpriseDB = true;
wxString version = output[0].AfterLast(' ');
int len=version.Length();
long actualMajor = 0, actualMinor = 0;
wxString tmp = wxT("");
int x = 0;
while(x<len&&(version[x] == '0' || version[x] == '1' || version[x] == '2' || version[x] == '3' || version[x] == '4' ||
version[x] == '5' || version[x] == '6' || version[x] == '7' || version[x] == '8' || version[x] == '9'))
{
tmp += version[x];
x++;
}
tmp.ToLong(&actualMajor);
x++;
tmp = wxT("");
while(x<len&&(version[x] == '0' || version[x] == '1' || version[x] == '2' || version[x] == '3' || version[x] == '4' ||
version[x] == '5' || version[x] == '6' || version[x] == '7' || version[x] == '8' || version[x] == '9'))
{
tmp += version[x];
x++;
}
tmp.ToLong(&actualMinor);
// EnterpriseDB's 8.3R1 utilties are based on PG8.2, so correct the version number here.
// This will need more work when 8.3R2 is released :-(
if (isEnterpriseDB && actualMajor == 8 && actualMinor == 3)
actualMinor = 2;
if (actualMajor > majorVer)
return true;
if (actualMajor == majorVer && actualMinor >= minorVer)
return true;
return false;
}
bool isPgApp(const wxString &app)
{
if (!wxFile::Exists(app))
return false;
wxArrayString output;
#ifdef __WXMSW__
if (wxExecute(app + wxT(" --version"), output, 0) != 0)
#else
if (ExecProcess(app + wxT(" --version"), output) != 0)
#endif
{
wxLogError(_("Failed to execute: %s --version"), app.c_str());
return false;
}
if (output[0].Contains(wxT("PostgreSQL")))
return true;
return false;
}
bool isEdbApp(const wxString &app)
{
if (!wxFile::Exists(app))
return false;
wxArrayString output;
#ifdef __WXMSW__
if (wxExecute(app + wxT(" --version"), output, 0) != 0)
#else
if (ExecProcess(app + wxT(" --version"), output) != 0)
#endif
{
wxLogError(_("Failed to execute: %s --version"), app.c_str());
return false;
}
if (output[0].Contains(wxT("EnterpriseDB")))
return true;
return false;
}
bool isGpApp(const wxString &app)
{
if (!wxFile::Exists(app))
return false;
wxArrayString output;
#ifdef __WXMSW__
if (wxExecute(app + wxT(" --version"), output, 0) != 0)
#else
if (ExecProcess(app + wxT(" --version"), output) != 0)
#endif
{
wxLogError(_("Failed to execute: %s --version"), app.c_str());
return false;
}
if (output[0].Contains(wxT("8.2"))) // Ugly... No way to tell Greenplum app from PostgreSQL 8.2 app
return true;
return false;
}
wxString sanitizePath(const wxString &path)
{
if (path.Length())
{
wxFileName fn = path;
fn.Normalize();
return fn.GetLongPath();
}
return wxEmptyString;
}
/**
* FUNCTION: commandLineCleanOption
* INPUTS:
* option - input string needs to be reformatted
* schemaObject - Is this an object related to schema?
* PURPOSE:
* - Fixup a (double-quoted) string for use on the command line
*/
wxString commandLineCleanOption(const wxString &option, bool schemaObject)
{
wxString tmp = option;
if (schemaObject)
{
// Replace double-quote with slash & double-quote
tmp.Replace(wxT("\""), wxT("\\\""));
}
else
{
// If required, clean the string to know the real object name
if (option.StartsWith(wxT("\"")) && option.EndsWith(wxT("\"")))
tmp = option.AfterFirst((wxChar)'"').BeforeLast((wxChar)'"');
// Replace single splash to double-splash
tmp.Replace(wxT("\\"), wxT("\\\\"));
// Replace double-quote with slash & double-quote
tmp.Replace(wxT("\""), wxT("\\\""));
// Replace double (slash & double-quote) combination to single (slash & double-quote) combination
tmp.Replace(wxT("\\\"\\\""), wxT("\\\""));
// Add the double quotes
tmp = wxT("\"") + tmp + wxT("\"");
}
return tmp;
}
#endif // PGSCLI
// Get an array from a comma separated list
bool getArrayFromCommaSeparatedList(const wxString &str, wxArrayString &res)
{
size_t len = str.Len(), index = 0, nBracketLevel = 0, startArray = 0;
bool inSingleQuote = false, inDoubleQuote = false;
if (len == 0)
return true;
for(; index < len; index++)
{
wxChar curr = str.GetChar(index);
if (!inDoubleQuote && curr == (wxChar)'\'')
inSingleQuote = !inSingleQuote;
else if (!inSingleQuote && curr == (wxChar)'"')
inDoubleQuote = !inDoubleQuote;
else if (!inDoubleQuote && !inSingleQuote && curr == (wxChar)'(')
nBracketLevel++;
else if (!inDoubleQuote && !inSingleQuote && curr == (wxChar)')')
nBracketLevel--;
else if (!inDoubleQuote && !inSingleQuote && nBracketLevel == 0 && curr == (wxChar)',')
{
if (index != startArray)
res.Add(str.SubString(startArray, index - 1).Trim(true).Trim(false));
else
res.Add(wxEmptyString);
startArray = index + 1;
}
}
if (inDoubleQuote || inSingleQuote || nBracketLevel != 0)
return false;
// Add last value to array
res.Add(str.SubString(startArray, index).Trim(true).Trim(false));
return true;
}
bool make_identifier(const wxString &strname, wxString &s, wxString &n, bool islower) {
s=strname.BeforeFirst('.');
if (s==strname) {
n=strname;
s="";
} else {
// full name
n=strname.AfterFirst('.');
}
//
if (n.Find('"')>=0) {
n.Replace("\"","");
} else {if (islower) n=n.MakeLower();}
if (s.Find('"')>=0) {
s.Replace("\"","");
} else {if (islower) s=s.MakeLower();}
return true;
}
// Get display for ScreenPoint
wxSize getScreenSizeForPoint(const wxPoint screenPos) {
// screen size
wxPoint posScreen;
wxSize sizeScreen;
const int displayNum = wxDisplay::GetFromPoint(screenPos);
if (displayNum != wxNOT_FOUND)
{
const wxRect rectScreen = wxDisplay(displayNum).GetGeometry();
posScreen = rectScreen.GetPosition();
sizeScreen = rectScreen.GetSize();
}
else // outside of any display?
{
// just use the primary one then
posScreen = wxPoint(0, 0);
sizeScreen = wxGetDisplaySize();
}
return sizeScreen;
}
//show help window
void showHelpHtml(wxWindow *parent, const wxString &htmlHelp,wxPoint screenPos, wxSize size) {
FunctionPGHelper fh(htmlHelp);
wxString key = "content";
wxSize sizeScreen=getScreenSizeForPoint(screenPos);
wxSize rr(350, 70);
if (size.x!=-1) rr=size;
popuphelp *m_Popup = new popuphelp(parent, key, &fh, screenPos, rr);
if (m_Popup && m_Popup->IsValid() && rr != m_Popup->GetSizePopup()) {
// recreate with new size
rr = m_Popup->GetSizePopup();
delete m_Popup;
m_Popup = new popuphelp((wxWindow*)winMain, key, &fh, screenPos, rr);
}
if (m_Popup && m_Popup->IsValid()) {
wxSize top_sz = m_Popup->GetSizePopup();
wxSize top_new(top_sz);
wxPoint p(screenPos);
wxPoint oldp(p);
if (p.x + top_new.x > sizeScreen.x) p.x = sizeScreen.x - top_new.x - 20;
if (p.y + top_new.y > sizeScreen.y) p.y = sizeScreen.y - top_new.y - 20;
if (oldp == p) p.x = p.x + 20;
m_Popup->Move(p);
wxRect r = m_Popup->GetScreenRect();
m_Popup->Popup();
}
//m_Popup->SetFocus();
}