/* * This file is part of rasdaman community. * * Rasdaman community is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Rasdaman community is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with rasdaman community. If not, see . * * Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / rasdaman GmbH. * * For more information please see * or contact Peter Baumann via . / /** * PURPOSE: * * rView query shell. Handles editing, loading, saving and execution * of RasQL queries. Actual database accesses are performed through * class rView's member functions. * * COMMENTS: * None */ // Standard wxWindows preamble. #ifdef __GNUG__ #pragma implementation #endif #include #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include #endif #include #include #include #ifdef EARLY_TEMPLATE #define __EXECUTABLE__ #endif #include "raslib/rmdebug.hh" #include "rviewApp.hh" #include "rviewUtils.hh" //#include "rviewDb.hh" #include "rviewQuery.hh" #include "rviewPrefs.hh" const int rviewQuery::query_width = 500; const int rviewQuery::query_height = 300; const int rviewQuery::query_border = 8; const int rviewQuery::query_bottom = 50; const int rviewQuery::query_bwidth = 80; const int rviewQuery::query_bheight = 40; const char rviewQuery::query_extension[] = ".ql"; const char rviewQuery::query_firstline[] = "-- rview-Query"; // The Query window counter int rviewQuery::queryCounter = 0; // Lookup tables for fonts. These have to be sorted case-sensitively! const keyword_to_ident_c rviewQuery::fontNameTab[] = { {wxDECORATIVE, "decorative"}, {wxDEFAULT, "default"}, {wxMODERN, "modern"}, {wxROMAN, "roman"}, {wxSCRIPT, "script"}, {wxSWISS, "swiss"}, {wxTELETYPE, "teletype"} }; const keyword_to_ident_c rviewQuery::fontStyleTab[] = { {wxITALIC, "italic"}, {wxSLANT, "slant"} }; const keyword_to_ident_c rviewQuery::fontWeightTab[] = { {wxBOLD, "bold"}, {wxLIGHT, "light"} }; rviewQuery::rviewQuery(rviewDatabase *db, char *query) : rviewFrame(NULL, NULL, 0, 0, query_width, query_height) { int w, h; const char *b; char *d; char buffer[STRINGSIZE]; int fontSize, fontName, fontStyle, fontWeight; const int fontNameSize = sizeof(fontNameTab) / sizeof(keyword_to_ident); const int fontStyleSize = sizeof(fontStyleTab) / sizeof(keyword_to_ident); const int fontWeightSize = sizeof(fontWeightTab) / sizeof(keyword_to_ident); RMDBGENTER(3, RMDebug::module_applications, "rviewQuery", "rviewQuery()"); queryDb = db; updateDisplay = NULL; CreateStatusLine(1); mbar = NULL; for (w=0; w<3; w++) mbarMenus[w] = NULL; if (::wxDirExists((char*)(prefs->queryPath.ptr()))) hotPath = prefs->queryPath; else hotPath = "."; // Read font from prefs b = prefs->queryFont; fontSize = 12; fontName = wxDEFAULT; fontStyle = wxNORMAL; fontWeight = wxNORMAL; while (*b != 0) { while ((*b == ' ') || (*b == ',')) b++; if (*b == 0) break; d = buffer; while ((*b != ' ') && (*b != ',') && (*b != 0)) {*d++ = *b++;} *d++ = 0; w = atoi(buffer); if (w != 0) fontSize = w; else { if ((w = rviewLookupKeyword(buffer, fontNameTab, fontNameSize, FALSE)) >= 0) fontName = w; else if ((w = rviewLookupKeyword(buffer, fontStyleTab, fontStyleSize, FALSE)) >= 0) fontStyle = w; else if ((w = rviewLookupKeyword(buffer, fontWeightTab, fontWeightSize, FALSE)) >= 0) fontWeight = w; else cerr << "Bad identifier in font string: " << buffer << endl; } } //cout << "size " << fontSize << ", name " << fontName << ", style " << fontStyle << ", weight " << fontWeight << endl; font = new wxFont(fontSize, fontName, fontStyle, fontWeight); //font = ::wxTheFontList->FindOrCreateFont(fontSize, fontName, fontStyle, fontWeight); //cout << "Font " << font->GetPointSize() << ',' << font->GetFamily() << ',' << font->GetStyle() << endl; GetClientSize(&w, &h); // Set identifier qwindowID = queryCounter++; updateID = -1; // no update object w -= 2*query_border; h -= query_bottom; twin = new wxTextWindow((wxWindow*)this, query_border, query_border, w, h - 2*query_border, wxBORDER | wxNATIVE_IMPL); twin->SetFont(font); panel = new wxPanel((wxWindow*)this, query_border, h, w, query_bottom); butClear = new rviewButton(panel); butExec = new rviewButton(panel); butUpdt = new rviewButton(panel); if (query != NULL) { twin->WriteText(query); } buildMenubar(); newDBState(rmanClientApp::theApp()->ReadDBState()); label(); OnSize(w, h); Show(TRUE); } rviewQuery::~rviewQuery(void) { // If an update window is open notify it. if (updateDisplay != NULL) { updateDisplay->noLongerUpdate(); } } const char *rviewQuery::getFrameName(void) const { return "rviewQuery"; } rviewFrameType rviewQuery::getFrameType(void) const { return rviewFrameTypeQuery; } void rviewQuery::OnSize(int w, int h) { int x, y; GetClientSize(&x, &y); if ((frameWidth == x) && (frameHeight == y)) return; frameWidth = x; frameHeight = y; x -= 2*query_border; y -= query_bottom; twin->SetSize(query_border, query_border, x, y - 2*query_border); panel->SetSize(query_border, y, x, query_bottom); y = (query_bottom - query_bheight) / 2; x = (x - 3*query_bwidth) / 3; butClear->SetSize(x/2, y, query_bwidth, query_bheight); butExec->SetSize((3*x)/2 + query_bwidth, y, query_bwidth, query_bheight); butUpdt->SetSize((5*x)/2 + 2*query_bwidth, y, query_bwidth, query_bheight); // doesn't work, unfortunately /*if (mbar != NULL) { int hw, hh; mbar->GetSize(&x, &y); mbarMenus[3]->GetSize(&hw, &hh); mbarMenus[3]->SetSize(x-hw, (y-hh)/2, hw, hh); }*/ } void rviewQuery::OnMenuCommand(int id) { // Load query from hotlist? if ((id >= MENU_QUERY_HOTLIST) && (id < MENU_QUERY_HOTLIST + hotNumber)) { char buffer[STRINGSIZE]; sprintf(buffer, "%s"DIR_SEPARATOR"%s%s", hotPath.ptr(), mbar->GetLabel(id), query_extension); loadQuery(buffer); return; } switch (id) { case MENU_QUERY_FILE_OPEN: case MENU_QUERY_FILE_SAVE: { char *name, *aux; char *prefDir = (char*)(hotPath.ptr()); char filter[16]; sprintf(filter, "*%s", query_extension); if (::wxDirExists(prefDir)) name = prefDir; else name = "."; name = ::wxFileSelector(lman->lookup((id == MENU_QUERY_FILE_OPEN) ? "titleQueryLoad" : "titleQuerySave"), name, NULL, NULL, filter, 0 , this); if (name != NULL) { aux = ::wxFileNameFromPath(name); if (strlen(aux) > 0) { if (id == MENU_QUERY_FILE_OPEN) { RMDBGONCE(3, RMDebug::module_applications, "rviewQuery", "loadQuery()"); loadQuery(name); } else { RMDBGONCE(3, RMDebug::module_applications, "rviewQuery", "saveQuery()"); saveQuery(name); } hotPath = ::wxPathOnly(name); prefs->queryPath = hotPath; prefs->markModified(); buildMenubar(); } } } break; case MENU_QUERY_FILE_EXIT: this->Close(TRUE); break; case MENU_QUERY_EDIT_CUT: twin->Cut(); break; case MENU_QUERY_EDIT_COPY: twin->Copy(); break; case MENU_QUERY_EDIT_PASTE: twin->Paste(); break; default: break; } } void rviewQuery::buildMenubar(void) { char pattern[STRINGSIZE], leaf[STRINGSIZE]; char *f; char *qhots[MENU_QUERY_HOTRANGE]; int i; wxMenu *hotList; // Do we actually need to rebuild the menu? if ((mbar != NULL) && (strcmp(hotPath, lastHotPath) == 0)) return; // build hotlist menu hotList = new wxMenu; sprintf(pattern, "%s"DIR_SEPARATOR"*%s", hotPath.ptr(), query_extension); // Sort the hotlist alphabetically f = ::wxFindFirstFile(pattern); hotNumber = 0; while (f && (hotNumber < MENU_QUERY_HOTRANGE)) { strcpy(leaf, ::wxFileNameFromPath(f)); f = strstr(leaf, query_extension); if (f != NULL) *f = '\0'; if ((qhots[hotNumber] = new char[strlen(leaf) + 1]) == NULL) break; strcpy(qhots[hotNumber], leaf); hotNumber++; f = wxFindNextFile(); } rviewQuicksortStrings(qhots, 0, hotNumber-1); for (i=0; iAppend(MENU_QUERY_HOTLIST + i, qhots[i]); delete [] qhots[i]; } if (mbar == NULL) { mbarMenus[0] = new wxMenu; mbarMenus[0]->Append(MENU_QUERY_FILE_OPEN, ""); mbarMenus[0]->Append(MENU_QUERY_FILE_SAVE, ""); mbarMenus[0]->Append(MENU_QUERY_FILE_EXIT, ""); mbarMenus[1] = new wxMenu; mbarMenus[1]->Append(MENU_QUERY_EDIT_CUT, ""); mbarMenus[1]->Append(MENU_QUERY_EDIT_COPY, ""); mbarMenus[1]->Append(MENU_QUERY_EDIT_PASTE, ""); mbarMenus[2] = hotList; mbar = new wxMenuBar; sprintf(pattern, "&%s", lman->lookup("menQueryFile")); mbar->Append(mbarMenus[0], pattern); sprintf(pattern, "&%s", lman->lookup("menQueryEdit")); mbar->Append(mbarMenus[1], pattern); sprintf(pattern, "&%s", lman->lookup("menQueryHotlist")); mbar->Append(mbarMenus[2], pattern); SetMenuBar(mbar); } else { mbar->Delete(mbarMenus[2], 2); sprintf(pattern, "&%s", lman->lookup("menQueryHotlist")); mbar->Append(hotList, pattern); delete mbarMenus[2]; mbarMenus[2] = hotList; } } void rviewQuery::label(void) { updateTitle(); mbar->SetLabel(MENU_QUERY_FILE_OPEN, lman->lookup("menQueryFileOpen")); mbar->SetLabel(MENU_QUERY_FILE_SAVE, lman->lookup("menQueryFileSave")); mbar->SetLabel(MENU_QUERY_FILE_EXIT, lman->lookup("menQueryFileClose")); mbar->SetHelpString(MENU_QUERY_FILE_OPEN, lman->lookup("helpQueryFileOpen")); mbar->SetHelpString(MENU_QUERY_FILE_SAVE, lman->lookup("helpQueryFileSave")); mbar->SetHelpString(MENU_QUERY_FILE_EXIT, lman->lookup("helpQueryFileClose")); mbar->SetLabel(MENU_QUERY_EDIT_CUT, lman->lookup("menQueryEditCut")); mbar->SetLabel(MENU_QUERY_EDIT_COPY, lman->lookup("menQueryEditCopy")); mbar->SetLabel(MENU_QUERY_EDIT_PASTE, lman->lookup("menQueryEditPaste")); mbar->SetHelpString(MENU_QUERY_EDIT_CUT, lman->lookup("helpQueryEditCut")); mbar->SetHelpString(MENU_QUERY_EDIT_COPY, lman->lookup("helpQueryEditCopy")); mbar->SetHelpString(MENU_QUERY_EDIT_PASTE, lman->lookup("helpQueryEditPaste")); mbar->SetLabelTop(0, lman->lookup("menQueryFile")); mbar->SetLabelTop(1, lman->lookup("menQueryEdit")); mbar->SetLabelTop(2, lman->lookup("menQueryHotlist")); butClear->SetLabel(lman->lookup("textClear")); butExec->SetLabel(lman->lookup("textExec")); butUpdt->SetLabel(lman->lookup("textUpdt")); } void rviewQuery::updateTitle(void) { if (updateID == -1) { SetTitle(lman->lookup("titleQuery")); } else { char buffer[STRINGSIZE]; sprintf(buffer, "%s q%dd%d", lman->lookup("titleQuery"), qwindowID, updateID); SetTitle(buffer); } } int rviewQuery::process(wxObject &obj, wxEvent &evt) { int type = evt.GetEventType(); if (type == wxEVENT_TYPE_BUTTON_COMMAND) { if (&obj == (wxObject*)butClear) { twin->Clear(); return 1; } if (&obj == (wxObject*)butExec) { int numl = twin->GetNumberOfLines(); int i, totalLength = 1; char *b, *query; query = twin->GetContents(); // Execute query. i = rmanClientApp::theApp()->executeQuery(query, (updateDisplay == NULL) ? NULL : &updateMddObj); // Did it fail? if (i == 0) { int line, column; // Was it a query error? if (queryDb->getErrorInfo(line, column) != 0) { long offset = twin->XYToPosition(column-1, line-1); // query was big enough to hold the entore query, so it's definitely // big enough to hold one line twin->GetLineText(line-1, query); b = query + column-1; while ((*b != ' ') && (!iscntrl(*b))) b++; twin->SetSelection(offset, offset + (long)(b - (query + column-1))); } } delete [] query; // Notify that we did something, not whether it was a success return 1; } if (&obj == (wxObject*)butUpdt) { rviewDisplay *newDisplay; // Don't set updateDisplay directly. We might have a valid update image and // issued a cancel from the file selection box. if ((newDisplay = (rviewDisplay*)rmanClientApp::theApp()->OpenFile(rviewDisplay::display_flag_update, &updateMddObj, FALSE)) != NULL) { if (updateDisplay != NULL) { updateDisplay->noLongerUpdate(); } updateDisplay = newDisplay; updateDisplay->setQueryWindow(qwindowID); updateID = updateDisplay->getIdentifier(); updateTitle(); return 1; } } } return 0; } int rviewQuery::getIdentifier(void) const { return qwindowID; } int rviewQuery::getQueryCounter(void) const { return queryCounter; } int rviewQuery::userEvent(const user_event &ue) { if ((ue.type == usr_db_opened) || (ue.type == usr_db_closed)) { newDBState((ue.type == usr_db_opened)); return 1; } if ((updateDisplay != NULL) && (ue.type == usr_update_closed)) { r_Ref *whichMdd = (r_Ref*)(ue.data); if (*whichMdd == updateMddObj) { updateDisplay = NULL; updateID = -1; updateTitle(); return 1; } } return 0; } void rviewQuery::newDBState(bool newState) { butExec->Enable(newState); } bool rviewQuery::loadQuery(char *file) { size_t length; int idlength; char *buffer, *b; FILE *fp; if ((fp = fopen(file, "rb")) == NULL) { char msg[STRINGSIZE]; sprintf(msg, "%s %s", lman->lookup("errorFileOpen"), file); rviewErrorbox::reportError(msg, rviewQuery::getFrameName(), "loadQuery"); return FALSE; } fseek(fp, 0, SEEK_END); length = ftell(fp); if ((buffer = new char[length+1]) == NULL) { rviewErrorbox::reportError(lman->lookup("errorMemory"), rviewQuery::getFrameName(), "loadQuery"); fclose(fp); return FALSE; } fseek(fp, 0, SEEK_SET); b = buffer; for (idlength=0; idlength<(int)length; idlength++) { int c; if ((c = fgetc(fp)) == EOF) break; #ifdef __VISUALC__ if (c != '\r') #endif *b++ = c; } *b++ = '\0'; if (idlength < (int)length) { char msg[STRINGSIZE]; sprintf(msg, "%s %s", lman->lookup("errorFileRead"), file); rviewErrorbox::reportError(msg, rviewQuery::getFrameName(), "loadQuery"); fclose(fp); return FALSE; } fclose(fp); idlength = strlen("RasDaView-Query"); if (strncmp(buffer, "RasDaView-Query", idlength) != 0) { idlength = strlen(query_firstline); if (strncmp(buffer,query_firstline, idlength) != 0) idlength = -1; } if (idlength < 0) { rviewErrorbox::reportError(lman->lookup("errorQueryFile"), rviewQuery::getFrameName(), "loadQuery"); delete [] buffer; return FALSE; } twin->Clear(); twin->WriteText(buffer + idlength + 1); delete [] buffer; return TRUE; } bool rviewQuery::saveQuery(char *file) { FILE *fp; char *buffer, *b, *upper; if ((fp = fopen(file, "wb")) == NULL) { char msg[STRINGSIZE]; sprintf(msg, "%s %s", lman->lookup("errorFileOpen"), file); rviewErrorbox::reportError(msg, rviewQuery::getFrameName(), "saveQuery"); return FALSE; } fprintf(fp, query_firstline); fputc('\n', fp); buffer = twin->GetContents(); b = buffer; upper = buffer + strlen(buffer); while (b < upper) { #ifdef __VISUALC__ if (*b != '\r') #endif if (fputc(*b, fp) != *b) break; b++; } if (b != upper) { char msg[STRINGSIZE]; sprintf(msg, "%s %s", lman->lookup("errorFileWrite"), file); rviewErrorbox::reportError(msg, rviewQuery::getFrameName(), "saveQuery"); fclose(fp); return FALSE; } fclose(fp); delete [] buffer; return TRUE; }