pgadmin3/frm/frmExport.cpp
lsv 9e9bfef8b8 fix without patch
Приведение в соответствие с github
Патч делать не нужно.
2022-04-27 16:01:13 +05:00

605 lines
16 KiB
C++

//////////////////////////////////////////////////////////////////////////
//
// pgAdmin III - PostgreSQL Tools
//
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
// frmExport.cpp - The export file dialogue
//
//////////////////////////////////////////////////////////////////////////
// App headers
#include "pgAdmin3.h"
#include <wx/file.h>
#include "frm/frmExport.h"
#include "utils/sysSettings.h"
#include "utils/misc.h"
#include "ctl/ctlSQLResult.h"
#include <wx/wx.h>
#include <wx/clipbrd.h>
#ifdef WIN32
#include <wx/msw/ole/automtn.h>
#endif
#define txtFilename CTRL_TEXT("txtFilename")
#define btnOK CTRL_BUTTON("wxID_OK")
#define rbUnicode CTRL_RADIOBUTTON("rbUnicode")
#define rbLocal CTRL_RADIOBUTTON("rbLocal")
#define rbCRLF CTRL_RADIOBUTTON("rbCRLF")
#define rbLF CTRL_RADIOBUTTON("rbLF")
#define rbQuoteStrings CTRL_RADIOBUTTON("rbQuoteStrings")
#define rbQuoteAll CTRL_RADIOBUTTON("rbQuoteAll")
#define rbQuoteNone CTRL_RADIOBUTTON("rbQuoteNone")
#define chkColnames CTRL_CHECKBOX("chkColnames")
#define chkXlsCopy CTRL_CHECKBOX("chkXlsCopy")
#define cbColSeparator CTRL_COMBOBOX("cbColSeparator")
#define cbQuoteChar CTRL_COMBOBOX("cbQuoteChar")
BEGIN_EVENT_TABLE(frmExport, pgDialog)
EVT_TEXT(XRCID("txtFilename"), frmExport::OnChange)
EVT_RADIOBUTTON(XRCID("rbQuoteNone"), frmExport::OnChange)
EVT_RADIOBUTTON(XRCID("rbQuoteStrings"), frmExport::OnChange)
EVT_RADIOBUTTON(XRCID("rbQuoteAll"), frmExport::OnChange)
EVT_BUTTON(XRCID("btnFilename"), frmExport::OnBrowseFile)
EVT_BUTTON(wxID_HELP, frmExport::OnHelp)
EVT_BUTTON(wxID_OK, frmExport::OnOK)
EVT_BUTTON(wxID_CANCEL, frmExport::OnCancel)
END_EVENT_TABLE()
class XMLDataFormat : public wxDataFormat
{
public:
XMLDataFormat() : wxDataFormat(wxT("XML Spreadsheet")) {}
};
class XMLDataObject : public wxDataObjectSimple
{
public:
XMLDataObject(const wxString& xmlstring = wxEmptyString) : wxDataObjectSimple(), m_XMLString(xmlstring)
{
SetFormat(XMLDataFormat());
}
size_t GetLength() const { return m_XMLString.Len()*2 + 1; }
wxString GetXML() const { return m_XMLString; }
void SetXML(const wxString& xml) { m_XMLString = xml; }
size_t GetDataSize() const
{
return GetLength();
}
bool GetDataHere(void *buf) const
{
//char* c = _strdup(m_XMLString.c_str()); not needed as per suggestion
//memcpy(buf, m_XMLString.c_str(), m_XMLString.Len()*2+1);
memcpy(buf,m_XMLString.mb_str(wxConvUTF8),m_XMLString.Len()*2+1);
return true;
}
bool SetData(size_t len, const void* buf)
{
//char* c = new char[len + 1]; not needed as per suggestion
//memcpy(c, buf, len); not needed as per suggestion
m_XMLString = wxString::FromUTF8((const char*)buf); //changed as per suggestion
//delete c;
return true;
}
virtual size_t GetDataSize(const wxDataFormat&) const
{
return GetDataSize();
}
virtual bool GetDataHere(const wxDataFormat&, void *buf) const
{
return GetDataHere(buf);
}
virtual bool SetData(const wxDataFormat&, size_t len, const void *buf)
{
return SetData(len, buf);
}
private:
wxString m_XMLString;
};
frmExport::frmExport(wxWindow *p)
{
parent = p;
SetFont(settings->GetSystemFont());
LoadResource(p, wxT("frmExport"));
RestorePosition();
// Icon
appearanceFactory->SetIcons(this);
cbQuoteChar->Disable();
btnOK->Disable();
bool uc = settings->GetExportUnicode();
rbUnicode->SetValue(uc);
rbLocal->SetValue(!uc);
bool isCrLf = settings->GetExportRowSeparator() == wxT("\r\n");
rbCRLF->SetValue(isCrLf);
rbLF->SetValue(!isCrLf);
int qt = settings->GetExportQuoting();
rbQuoteNone->SetValue(qt == 0);
rbQuoteStrings->SetValue(qt == 1);
rbQuoteAll->SetValue(qt == 2);
cbColSeparator->SetValue(settings->GetExportColSeparator());
cbQuoteChar->SetValue(settings->GetExportQuoteChar());
wxString val;
settings->Read(wxT("Export/LastFile"), &val, wxEmptyString);
txtFilename->SetValue(val);
wxCommandEvent ev;
OnChange(ev);
}
frmExport::~frmExport()
{
SavePosition();
}
void frmExport::OnHelp(wxCommandEvent &ev)
{
DisplayHelp(wxT("export"), HELP_PGADMIN);
}
void frmExport::OnChange(wxCommandEvent &ev)
{
cbQuoteChar->Enable(rbQuoteStrings->GetValue() || rbQuoteAll->GetValue());
btnOK->Enable(!txtFilename->GetValue().IsEmpty() && !cbColSeparator->GetValue().IsEmpty());
}
void frmExport::OnOK(wxCommandEvent &ev)
{
settings->SetExportUnicode(rbUnicode->GetValue());
settings->SetExportRowSeparator(rbCRLF->GetValue() ? wxT("\r\n") : wxT("\n"));
settings->SetExportColSeparator(cbColSeparator->GetValue());
if (rbQuoteAll->GetValue())
settings->SetExportQuoting(2);
else if (rbQuoteStrings->GetValue())
settings->SetExportQuoting(1);
else
settings->SetExportQuoting(0);
settings->SetExportQuoteChar(cbQuoteChar->GetValue());
settings->Write(wxT("Export/LastFile"), txtFilename->GetValue());
if (IsModal())
EndModal(wxID_OK);
else
Destroy();
}
wxString frmExport::InitXml(int cols, int rows)
{
wxString strc;
wxString strr;
strc.Printf(wxT("%d"),cols);
strr.Printf(wxT("%d"),rows);
wxString s= wxT("<?xml version=\"1.0\"?>\n")
wxT("<?mso-application progid=\"Excel.Sheet\"?>\n")
wxT("<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\"\n")
wxT(" xmlns:o=\"urn:schemas-microsoft-com:office:office\"\n")
wxT("xmlns:x=\"urn:schemas-microsoft-com:office:excel\"\n")
wxT("xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\"\n")
wxT("xmlns:html=\"http://www.w3.org/TR/REC-html40\">\n")
wxT("<Styles>\n")
wxT("<Style ss:ID=\"def\">\n")
wxT("<Borders>\n")
wxT("<Border ss:Position=\"Bottom\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>\n")
wxT("<Border ss:Position=\"Left\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>\n")
wxT("<Border ss:Position=\"Right\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>\n")
wxT("<Border ss:Position=\"Top\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>\n")
wxT("</Borders></Style>\n")
wxT("<Style ss:ID=\"hdr\">\n")
wxT("<Borders>\n")
wxT("<Border ss:Position=\"Bottom\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>\n")
wxT("<Border ss:Position=\"Left\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>\n")
wxT("<Border ss:Position=\"Right\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>\n")
wxT("<Border ss:Position=\"Top\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>\n")
wxT("</Borders><Font ss:FontName=\"Arial Cyr\" x:CharSet=\"204\" ss:Bold=\"1\"/></Style>\n")
wxT("<Style ss:ID=\"dt\">\n")
wxT("<Borders>\n")
wxT("<Border ss:Position=\"Bottom\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>\n")
wxT("<Border ss:Position=\"Left\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>\n")
wxT("<Border ss:Position=\"Right\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>\n")
wxT("<Border ss:Position=\"Top\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>\n")
wxT("</Borders><NumberFormat ss:Format=\"General Date\"/></Style>\n")
wxT("<Style ss:ID=\"null\">\n")
wxT("<Borders>\n")
wxT("<Border ss:Position=\"Bottom\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>\n")
wxT("<Border ss:Position=\"Left\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>\n")
wxT("<Border ss:Position=\"Right\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>\n")
wxT("<Border ss:Position=\"Top\" ss:LineStyle=\"Continuous\" ss:Weight=\"1\"/>\n")
wxT("</Borders><Interior ss:Color=\"#CCFFCC\" ss:Pattern=\"Solid\"/></Style>\n")
wxT("</Styles>\n")
wxT("<Worksheet ss:Name=\"data\">\n")
wxT("<Table ss:ExpandedColumnCount=\"")+strc+wxT("\" ss:ExpandedRowCount=\"")+strr+wxT("\">\n")
wxT("\n")
;
for (int c = 0 ; c < cols ; c++)
{
s+=wxT("<Column ss:AutoFitWidth=\"1\"/>\n");
}
return s;
}
wxString textEscapeXml(wxString &text)
{
wxString::const_iterator i;
wxString xmltext=wxEmptyString;
for ( i = text.begin(); i != text.end(); ++i )
{
#if wxCHECK_VERSION(3, 0, 0)
char c=*i;
switch (c)
#else
switch (*i)
#endif
{
case '&': xmltext+= wxT("&amp;"); break;
case '\'': xmltext+= wxT("&apos;"); break;
case '"': xmltext+= wxT("&quot;"); break;
case '<': xmltext+= wxT("&lt;"); break;
case '>': xmltext+= wxT("&gt;"); break;
case 13: break;
case 10: xmltext+= wxT("&#10;"); break;
default: xmltext+= *i; break;
}
}
return xmltext;
}
bool frmExport::ExportXls(ctlSQLResult *grid)
{
int colCount, rowCount;
int col;
wxString line;
long skipped = 0;
wxWX2MBbuf buf;
colCount = grid->GetNumberCols();
rowCount = grid->NumRows();
line=InitXml(colCount,rowCount+1);
line += wxT("<Row>\n");
for (col = 0 ; col < colCount ; col++)
{
line += wxT("<Cell ss:StyleID=\"hdr\"><Data ss:Type=\"String\">")+grid->OnGetItemText(-1, col + 1).BeforeFirst('\n')+wxT("</Data></Cell>");
//wxString adr(wxT(""));
//adr.Printf(wxT("%s%d"), name,1);
//rng[0] = wxVariant(adr);
//excelObject.GetObject(range, wxT("Range"), 1,rng);
//range.CallMethod(wxT("Activate"));
//excelObject.PutProperty(wxT("ActiveCell.Font.Bold"), true);
//excelObject.PutProperty(wxT("ActiveCell.Value"), grid->OnGetItemText(-1, col + 1).BeforeFirst('\n'));
//name[0]++;
}
line += wxT("</Row>\n");
int row;
wxString text;
wxString type;
OID typOid;
wxString fn=txtFilename->GetValue().BeforeLast('.');
if (fn.IsEmpty()) fn=txtFilename->GetValue()+wxT(".xml");
else fn+=wxT(".xml");
wxFile file(fn, wxFile::write);
if (!file.IsOpened())
{
wxLogError(__("Failed to open file %s."), fn.c_str());
return false;
}
file.Write(line, wxConvUTF8);
wxString xmltext=wxEmptyString;
for (row = 0 ; row < rowCount ; row++)
{
if (grid->GetRowSize(row)==0) continue;
line = wxT("<Row>\n");
for (col = 0 ; col < colCount ; col++)
{
wxString style(wxT("null"));
//adr.Printf(wxT("%s%d"), name,row+2);
//rng[0] = wxVariant(adr);
//excelObject.GetObject(range, wxT("Range"), 1,rng);
//range.CallMethod(wxT("Activate"));
text=grid->OnGetItemText(row, col + 1);
xmltext=wxEmptyString;
typOid = grid->colTypClasses[col];
if (!text.IsEmpty()) {
style=wxT("def");
xmltext=textEscapeXml(text);
// find out if string
switch (typOid)
{
case PGTYPCLASS_NUMERIC:
//type=wxT("0.00");
if (xmltext.IsNumber())
xmltext=wxT("<Cell ss:StyleID=\"")+style+wxT("\"><Data ss:Type=\"Number\">")+xmltext+wxT("</Data></Cell>");
else
xmltext=wxT("<Cell ss:StyleID=\"")+style+wxT("\"><Data ss:Type=\"String\">")+xmltext+wxT("</Data></Cell>");
break;
case PGTYPCLASS_DATE:
//
xmltext=xmltext.BeforeFirst('+');
if (xmltext.Replace(wxT(" "),wxT("T"))==0) {
xmltext=wxT("<Cell ss:StyleID=\"")+style+wxT("\"><Data ss:Type=\"String\">")+xmltext+wxT("</Data></Cell>");
} else
{
style=wxT("dt");
xmltext=wxT("<Cell ss:StyleID=\"")+style+wxT("\"><Data ss:Type=\"DateTime\">")+xmltext+wxT("</Data></Cell>");
}
break;
case PGTYPCLASS_BOOL:
default:
//type=wxT("@");
xmltext=wxT("<Cell ss:StyleID=\"")+style+wxT("\"><Data ss:Type=\"String\">")+xmltext+wxT("</Data></Cell>");
break;
}
} else xmltext=wxT("<Cell ss:StyleID=\"null\"/>");
// excelObject.PutProperty(wxT("ActiveCell.Borders.LineStyle"), 1);
// excelObject.PutProperty(wxT("ActiveCell.NumberFormat"),type);
// excelObject.PutProperty(wxT("ActiveCell.Value"), text);
// name[0]++;
line += xmltext+wxT("\n");
}
line += wxT("</Row>\n");
file.Write(line, wxConvUTF8);
}
line = wxT("</Table></Worksheet>");
file.Write(line, wxConvUTF8);
text=textEscapeXml(grid->sqlquerytext);
line= wxT("<Worksheet ss:Name=\"SQL text\">\n")
wxT("<Table ss:ExpandedColumnCount=\"1\" ss:ExpandedRowCount=\"1\">\n")
wxT("<Column ss:Width=\"300\"/><Row ss:AutoFitHeight=\"1\">\n")
wxT("<Cell><Data ss:Type=\"String\">")+text+
wxT("\n</Data></Cell></Row></Table></Worksheet>")
wxT("</Workbook>\n")
;
file.Write(line, wxConvUTF8);
file.Close();
#ifdef WIN32
wxAutomationObject excelObject;
if (excelObject.CreateInstance(wxT("Excel.Application"))) {
//excelObject.GetObject(xlbook,wxT("Workbooks.Add"));
excelObject.CallMethod(wxT("Workbooks.Open"), fn);
excelObject.PutProperty(_T("VISIBLE"), true);
return true;
}
#endif
return false;
}
bool frmExport::Export(pgSet *set)
{
ctlSQLResult *grid = 0;
if (!set)
{
wxLogInfo(wxT("Exporting data from the grid"));
grid = (ctlSQLResult *)parent;
if (chkXlsCopy->GetValue()) {
return ExportXls(grid);
}
}
else
wxLogInfo(wxT("Exporting data from a resultset"));
wxFile file(txtFilename->GetValue(), wxFile::write);
if (!file.IsOpened())
{
wxLogError(__("Failed to open file %s."), txtFilename->GetValue().c_str());
return false;
}
wxString line;
long skipped = 0;
wxWX2MBbuf buf;
int colCount, rowCount;
if (set)
{
colCount = set->NumCols();
rowCount = set->NumRows();
}
else
{
colCount = grid->GetNumberCols();
rowCount = grid->NumRows();
}
int col;
if (chkColnames->GetValue())
{
for (col = 0 ; col < colCount ; col++)
{
if (!col)
line = wxEmptyString;
else
line += cbColSeparator->GetValue();
if (rbQuoteStrings->GetValue() || rbQuoteAll->GetValue())
{
wxString qc = cbQuoteChar->GetValue();
wxString hdr;
if (set)
hdr = set->ColName(col);
else
hdr = grid->OnGetItemText(-1, col + 1).BeforeFirst('\n');
hdr.Replace(qc, qc + qc);
line += qc + hdr + qc;
}
else
{
if (set)
line += set->ColName(col);
else
line += grid->OnGetItemText(-1, col + 1).BeforeFirst('\n');
}
}
if (rbCRLF->GetValue())
line += wxT("\r\n");
else
line += wxT("\n");
if (rbUnicode->GetValue())
file.Write(line, wxConvUTF8);
else
{
buf = line.mb_str(wxConvLibc);
if (!buf)
skipped++;
else
file.Write(line, wxConvLibc);
}
}
wxString text;
OID typOid;
int row;
for (row = 0 ; row < rowCount ; row++)
{
for (col = 0 ; col < colCount ; col++)
{
if (!col)
line = wxEmptyString;
else
line += cbColSeparator->GetValue();
bool needQuote = rbQuoteAll->GetValue();
if (set)
{
text = set->GetVal(col);
typOid = set->ColTypClass(col);
}
else
{
text = grid->OnGetItemText(row, col + 1);
typOid = grid->colTypClasses[col];
}
if (!needQuote && rbQuoteStrings->GetValue())
{
// find out if string
switch (typOid)
{
case PGTYPCLASS_NUMERIC:
case PGTYPCLASS_BOOL:
break;
default:
needQuote = true;
break;
}
}
if (needQuote)
{
wxString qc = cbQuoteChar->GetValue();
text.Replace(qc, qc + qc);
line += qc + text + qc;
}
else
line += text;
}
if (rbCRLF->GetValue())
line += wxT("\r\n");
else
line += wxT("\n");
if (rbUnicode->GetValue())
file.Write(line, wxConvUTF8);
else
{
buf = line.mb_str(wxConvLibc);
if (!buf)
skipped++;
else
file.Write(line, wxConvLibc);
}
if (set)
set->MoveNext();
}
file.Close();
if (skipped)
wxLogError(wxPLURAL(
"Data export incomplete.\n\n%d row contained characters that could not be converted to the local charset.\n\nPlease correct the data or try using UTF8 instead.",
"Data export incomplete.\n\n%d rows contained characters that could not be converted to the local charset.\n\nPlease correct the data or try using UTF8 instead.",
skipped), skipped);
else
wxMessageBox(_("Data export completed successfully."), _("Export data"), wxICON_INFORMATION | wxOK);
return true;
}
void frmExport::OnCancel(wxCommandEvent &ev)
{
if (IsModal())
EndModal(wxID_CANCEL);
else
Destroy();
}
void frmExport::OnBrowseFile(wxCommandEvent &ev)
{
wxString directory;
wxString filename;
if (txtFilename->GetValue().IsEmpty())
directory = wxGetHomeDir();
else
{
directory = wxFileName(txtFilename->GetValue()).GetPath();
filename = wxFileName(txtFilename->GetValue()).GetFullName();
}
#ifdef __WXMSW__
wxFileDialog file(this, _("Select export filename"), directory, filename,
_("CSV files (*.csv)|*.csv|Data files (*.dat)|*.dat|All files (*.*)|*.*"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
#else
wxFileDialog file(this, _("Select export filename"), directory, filename,
_("CSV files (*.csv)|*.csv|Data files (*.dat)|*.dat|All files (*)|*"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
#endif
if (file.ShowModal() == wxID_OK)
{
txtFilename->SetValue(file.GetPath());
OnChange(ev);
}
}