示例#1
0
int CDBAPI_CacheAdmin::Connect(const CArgs& args)
{
    CDriverManager &db_drv_man = CDriverManager::GetInstance();
    string drv_name;
    DBAPI_RegisterDriver_FTDS();
    drv_name = "ftds";

    IDataSource* ds = db_drv_man.CreateDs(drv_name);

    if (ds == 0) {
        ERR_POST_X(1, Error << "Cannot init driver: " << drv_name);
        return 1;
    }

    m_Conn.reset(ds->CreateConnection());
    if (m_Conn.get() == 0) {
        ERR_POST_X(2, "Cannot create connection. Driver: " << drv_name);
        return 1;
    }

    string server   = args["s"].AsString();
    string database = args["d"].AsString();
    string user     = args["u"].AsString();
    string passwd   = args["p"].AsString();

    m_Conn->Connect(user, passwd, server, database);

    m_Cache.Open(&*m_Conn);

    return 0;
}
示例#2
0
uint32 DirFile::getSize(const std::string& name)
{
	FileSystem* filesys = FileSystem::get_instance();
	IDataSource* ids = filesys->ReadFile(path + name);
	if (!ids) return 0;

	uint32 size = ids->getSize();
	delete ids;
	return size;
}
示例#3
0
void TestUI::open()
{
	assert(test1Views_.size() < 5);

	IDataSourceManager* dataSrcMngr = get<IDataSourceManager>();
	IDataSource* dataSrc = dataSrcMngr->openDataSource();

	IEnvManager* em = get<IEnvManager>();
	int envIdx = em->addEnv( dataSrc->description() );

	dataSrcEnvPairs_.push_back( DataSrcEnvPairs::value_type( dataSrc, envIdx ) );
	createViews( *fw_, dataSrc, envIdx );
}
示例#4
0
void SHP2ASCDlg::OnCOpenIshpClick( wxCommandEvent& event )
{
    try{
        ConnectDatasourceDlg dlg(this);
        if (dlg.ShowModal() != wxID_OK) return;
        
        wxString proj_title = dlg.GetProjectTitle();
        wxString layer_name = dlg.GetLayerName();
        IDataSource* datasource = dlg.GetDataSource();
        wxString ds_name = datasource->GetOGRConnectStr();
        GdaConst::DataSourceType ds_type = datasource->GetType();
        
        ogr_ds = new OGRDatasourceProxy(ds_name, ds_type, true);
        ogr_layer = ogr_ds->GetLayerProxy(layer_name.ToStdString());
        ogr_layer->ReadData();

        bool is_valid_layer = true;
        
        if (ogr_layer->IsTableOnly()) {
            wxMessageBox("This is not a shape datasource. Please open a valid "
                         "shape datasource, e.g. ESRI Shapefile, PostGIS layer...");
            is_valid_layer = false;
        }
        if (ogr_layer->GetNumFields() == 0){
            wxMessageBox("No fields found!");
            is_valid_layer = false;
        }
        if ( !is_valid_layer) {
            delete ogr_ds;
            ogr_ds = NULL;
            return;
        }
        
        m_X->Clear();
        for (int i=0; i<ogr_layer->GetNumFields(); i++){
            m_X->Append(wxString::Format("%s",ogr_layer->GetFieldName(i)));
        }
        m_X->SetSelection(0);
        m_inputfile->SetValue(layer_name);
        
        FindWindow(XRCID("IDC_OPEN_OASC"))->Enable(true);
        FindWindow(XRCID("IDC_FIELD_ASC"))->Enable(true);
        FindWindow(XRCID("IDC_KEYVAR"))->Enable(true);
    } catch (GdaException& e) {
        wxMessageDialog dlg (this, e.what(), "Error", wxOK | wxICON_ERROR);
		dlg.ShowModal();
        return;
    }
}
示例#5
0
uint8* DirFile::getObject(const std::string& name, uint32* sizep)
{
	FileSystem* filesys = FileSystem::get_instance();
	IDataSource* ids = filesys->ReadFile(path + name);
	if (!ids) return 0;

	uint32 size = ids->getSize();
	if (size == 0) return 0;

	uint8* buf = new uint8[size];
	ids->read(buf, size);
	delete ids;

	if (sizep) *sizep = size;

	return buf;
}
示例#6
0
    //! Seek Vorbis Data
    int VorbisSeek(void *datasource,ogg_int64_t offset,int whence)
    {
        IDataSource* Stream = (IDataSource*)datasource;
        switch (whence)
        {
        case SEEK_SET:
            Stream->seek(offset, false);
            break;

        case SEEK_CUR:
            Stream->seek(offset, true);
            break;

        case SEEK_END:
            Stream->seek(Stream->getSize()-offset, false);
            break;
        };
        return 0;
    }
示例#7
0
void ImageItem::updateItemSize(DataSourceManager* dataManager, RenderPass pass, int maxHeight)
{
   if (!m_datasource.isEmpty() && !m_field.isEmpty() && m_picture.isNull()){
       IDataSource* ds = dataManager->dataSource(m_datasource);
       if (ds) {
          QVariant data = ds->data(m_field);
          if (data.isValid()){
              if (data.type()==QVariant::Image){
                m_picture =  data.value<QImage>();
              } else
                m_picture.loadFromData(data.toByteArray());
          }
       }
   }
   if (m_autoSize){
       setWidth(m_picture.width());
       setHeight(m_picture.height());
   }
   BaseDesignIntf::updateItemSize(dataManager, pass, maxHeight);
}
示例#8
0
    IAudioSource* cAudioManager::create(const char* name, const char* filename, bool stream)
    {
		if(!Initialized) return NULL;

		cAudioMutexBasicLock lock(Mutex);
		cAudioString audioName = safeCStr(name);
		cAudioString path = safeCStr(filename);
		cAudioString ext = getExt(path);
		IAudioDecoderFactory* factory = getAudioDecoderFactory(ext.c_str());

		if(!factory) {
			getLogger()->logError("AudioManager", "Failed to create Audio Source (%s): No decoder could be found for (.%s).", audioName.c_str(), ext.c_str());
			return NULL;
		}

		for(size_t i=0; i<dataSourcePriorityList.size(); ++i)
		{
			const cAudioString dataSourceName = dataSourcePriorityList[i].second;
			IDataSourceFactory* dataFactory = datasourcemap[dataSourceName];
			if(dataFactory)
			{
				IDataSource* source = dataFactory->CreateDataSource(filename, stream);
				if(source && source->isValid())
				{
					IAudioDecoder* decoder = factory->CreateAudioDecoder(source);
					source->drop();

					IAudioSource* audio = createAudioSource(decoder, audioName, dataSourceName);
					if(audio != NULL)
						return audio;

					if(source)
						source->drop();

					return NULL;
				}
			}
		}		
		return NULL;
    }
示例#9
0
    IAudioBuffer* cAudioManager::createBuffer(const char* filename)
    {
		if(!Initialized) return NULL;

		cAudioMutexBasicLock lock(Mutex);
		cAudioString path = fromUTF8(filename);
		cAudioString ext = getExt(path);
		IAudioDecoderFactory* factory = getAudioDecoderFactory(toUTF8(ext));

		if(!factory) {
			getLogger()->logError("AudioManager", "Failed to create Audio Buffer: No decoder could be found for (.%s).", toUTF8(ext));
			return NULL;
		}

		for(size_t i=0; i<dataSourcePriorityList.size(); ++i)
		{
			const cAudioString dataSourceName = dataSourcePriorityList[i].second;
			IDataSourceFactory* dataFactory = datasourcemap[dataSourceName];
			if(dataFactory)
			{
				IDataSource* source = dataFactory->CreateDataSource(filename, false);
				if(source && source->isValid())
				{
					IAudioDecoder* decoder = factory->CreateAudioDecoder(source);
					source->drop();

                    IAudioBuffer* buffer = CAUDIO_NEW cAudioBuffer(decoder);

					if(buffer != NULL)
						return buffer;

					//if(source)
					//	source->drop();

					return NULL;
				}
			}
		}
		return NULL;
    }
示例#10
0
CDriverManager::~CDriverManager()
{
    try {
        CMutexGuard mg(m_Mutex);

        ITERATE(TDsContainer, it, m_ds_list) {
            IDataSource* ds = it->second;

            if (ds) {
                // We won't delete IDataSource unless all connections
                // are closed, because deleting of IDataSource will also
                // delete all connections.
                // This will cause a memory leak but it also will prevent from
                // accessing an already freed memory or even application
                // crash..
                if (ds->GetDriverContext()->NofConnections() == 0) {
                    delete ds;
                }
            }
        }

        m_ds_list.clear();
    }
示例#11
0
TTF_Font* FontManager::getTTF_Font(std::string filename, int pointsize)
{
	TTFId id;
	id.filename = filename;
	id.pointsize = pointsize;

	std::map<TTFId, TTF_Font*>::iterator iter;
	iter = ttf_fonts.find(id);

	if (iter != ttf_fonts.end())
		return iter->second;

	IDataSource* fontids;
	fontids = FileSystem::get_instance()->ReadFile("@data/" + filename);
	if (!fontids) {
		perr << "Failed to open TTF: @data/" << filename << std::endl;
		return 0;
	}

	// open font using SDL_RWops.
	// Note: The RWops and IDataSource will be deleted by the TTF_Font
	TTF_Font* font = TTF_OpenFontRW(fontids->getRWops(), 1, pointsize);

	if (!font) {
		perr << "Failed to open TTF: @data/" << filename
			 << ": " << TTF_GetError() << std::endl;
		return 0;
	}

	ttf_fonts[id] = font;

#ifdef DEBUG
	pout << "Opened TTF: @data/" << filename << "." << std::endl;
#endif

	return font;
}
示例#12
0
 //! Read Vorbis Data
 size_t VorbisRead(void *ptr, size_t byteSize,size_t sizeToRead, void *datasource)
 {
     IDataSource* Stream = (IDataSource*)datasource;
     return Stream->read(ptr,byteSize*sizeToRead);
 }
示例#13
0
void SKFPlayer::run()
{
	if (!playing || !buffer) return;

	// if doing something, continue
	if (curaction) {
		if (curaction == SKF_FadeOut || curaction == SKF_FadeWhite) {
			fadelevel++;
			if (fadelevel == FADESTEPS) curaction = 0; // done
		} else if (curaction == SKF_FadeIn) {
			fadelevel--;
			if (fadelevel == 0) curaction = 0; // done
		} else {
			pout << "Unknown fade action: " << curaction << std::endl;
		}
	}

	// CHECKME: this timing may not be accurate enough...
	uint32 now = SDL_GetTicks();
	if (lastupdate + (1000/framerate) > now) return;

	lastupdate += (1000/framerate);

	// if waiting, continue to wait
	if (timer) {
		timer--;
		return;
	}

	Pentagram::Font* redfont;
	redfont = FontManager::get_instance()->getGameFont(6, true);

	MusicProcess* musicproc = MusicProcess::get_instance();
	AudioProcess* audioproc = AudioProcess::get_instance();

	// handle events for the current frame
	while (curevent < events.size() && events[curevent]->frame <= curframe) {
//		pout << "event " << curevent << std::endl;
		switch (events[curevent]->action)
		{
		case SKF_FadeOut:
			curaction = SKF_FadeOut;
			fadecolour = 0;
			fadelevel = 0;
//			pout << "FadeOut" << std::endl;
			break;
		case SKF_FadeIn:
			curaction = SKF_FadeIn;
			fadelevel = FADESTEPS;
//			pout << "FadeIn" << std::endl;
			break;
		case SKF_FadeWhite:
			curaction = SKF_FadeWhite;
			fadecolour = 0xFF;
			fadelevel = 0;
//			pout << "FadeWhite" << std::endl;
			break;
		case SKF_Wait:
//			pout << "Wait " << events[curevent]->data << std::endl;
			timer = events[curevent]->data;
			curevent++;
			return;
		case SKF_PlayMusic:
//			pout << "PlayMusic " << events[curevent]->data << std::endl;
			if (musicproc) musicproc->playMusic(events[curevent]->data);
			break;
		case SKF_SlowStopMusic:
			POUT ("SlowStopMusic");
			if (musicproc && !introMusicHack) musicproc->playMusic(0);
			break;
		case SKF_PlaySFX:
//			pout << "PlaySFX " << events[curevent]->data << std::endl;
			if (audioproc) audioproc->playSFX(events[curevent]->data,0x60,0,0);
			break;
		case SKF_StopSFX:
//			pout << "StopSFX" << events[curevent]->data << std::endl;
			if (audioproc) audioproc->stopSFX(events[curevent]->data,0);
			break;
		case SKF_SetSpeed:
			POUT("SetSpeed " << events[curevent]->data);
//			framerate = events[curevent]->data;
			break;
		case SKF_PlaySound:
		{
//			pout << "PlaySound " << events[curevent]->data << std::endl;

			if (audioproc) {
				uint8* buffer = skf->get_object(events[curevent]->data);
				uint32 bufsize = skf->get_size(events[curevent]->data);
				Pentagram::AudioSample* s;
				uint32 rate = buffer[6] + (buffer[7]<<8);
				bool stereo = (buffer[8] == 2);
				s = new Pentagram::RawAudioSample(buffer+34, bufsize-34,
												  rate, true, stereo);
				audioproc->playSample(s, 0x60, 0);
				// FIXME: memory leak! (sample is never deleted)
			}

			// subtitles
			char* textbuf = reinterpret_cast<char*>(
				skf->get_object(events[curevent]->data-1));
			uint32 textsize = skf->get_size(events[curevent]->data-1);
			if (textsize > 7) {
				std::string subtitle = (textbuf+6);
				delete subs;
				subtitley = textbuf[4] + (textbuf[5]<<8);
				unsigned int remaining;
				subs = redfont->renderText(subtitle, remaining, 200, 0,
										   Pentagram::Font::TEXT_CENTER);
			}
			delete textbuf;


			break;
		}
		case SKF_ClearSubs:
//			pout << "ClearSubs" << std::endl;
			delete subs;
			subs = 0;
			break;
		default:
			pout << "Unknown action" << std::endl;
			break;
		}

		curevent++;
	}

	curframe++;

	PaletteManager* palman = PaletteManager::get_instance();
	IDataSource* object;

	uint16 objecttype = 0;
	do {
		curobject++;
		if (curobject >= skf->getCount()) {
			stop(); // done
			return;
		}

		// read object
		object = skf->get_datasource(curobject);
		if (!object || object->getSize() < 2)
			continue;

		objecttype = object->read2();

//		pout << "Object " << curobject << "/" << skf->getCount()
//			 << ", type = " << objecttype << std::endl;


		if (objecttype == 1) {
			palman->load(PaletteManager::Pal_Movie, *object);
		}

		if (objecttype != 2)
			delete object;

	} while (objecttype != 2);

	if (objecttype == 2) {
		object->seek(0);
		Shape* shape = new Shape(object, &U8SKFShapeFormat);
		Pentagram::Palette* pal= palman->getPalette(PaletteManager::Pal_Movie);
		shape->setPalette(pal);
		buffer->BeginPainting();
		buffer->Paint(shape, 0, 0, 0);
		buffer->EndPainting();
		delete shape;
	
		delete object;
	}

	timer = 1; // HACK! timing is rather broken currently...
}
示例#14
0
bool loadPalette(Pentagram::Palette * pal, const ConvertShapeFormat * format)
{
	GimpRGB color;
	guchar palHack[2];
	palHack[1] = 255;
	bool newPal;
	const gchar * palName;

	for (int i = 0; i < 256; ++i)
	{
		palHack[0] = i;
		pal->native[i] = *((uint16 * ) palHack);
	}

	if (format == &PentagramShapeFormat)
	{
		palName = "Pentagram";
	}
	else if (format == &U8SKFShapeFormat)
	{
		palName = "U8SKF";
	}
	else if (format == &U8ShapeFormat)
	{
		palName = "Ultima8";
	}
	else if (format == &U82DShapeFormat)
	{
		palName = "Ultima8";
	}
	else if (format == &CrusaderShapeFormat)
	{
		palName = "Crusader";
	}
	else if (format == &Crusader2DShapeFormat)
	{
		palName = "Crusader";
	}
	else
	{
		return false;
	}

	newPal = ! gimp_context_set_palette(palName);
	if (newPal)
	{
		gint colors = 0;
		if (gimp_palette_get_info(palName, &colors))
		{
			newPal = false;
			if (colors != 256)
			{
				newPal = true;
				if (!gimp_palette_delete(palName))
					return false;
			}
		}
	}

	if (newPal)
	{
		if (g_ascii_strcasecmp(palName, gimp_palette_new(palName)))
			return false;
		if (!gimp_context_set_palette(palName))
			return false;

		IDataSource * ds = choosePalette();
		if (ds)
		{
			gint j = 0;
			ds->seek(4);
			pal->load(*ds);
			delete ds;
			for (gint i = 0; i < 256; ++i)
			{
				gimp_rgb_set_uchar(&color,
							pal->palette[i * 3],
							pal->palette[i * 3 + 1],
							pal->palette[i * 3 + 2]);
				gimp_palette_add_entry(palName, "Untitled", &color, &j);
				assert (j == i);
			}
		}
		else
		{
			return false;
		}
	}
	else
	{
		for (gint i = 0; i < 256; ++i)
		{
			gimp_palette_entry_get_color(palName, i, &color);
			gimp_rgb_get_uchar(&color,
						&(pal->palette[i * 3]),
						&(pal->palette[i * 3 + 1]),
						&(pal->palette[i * 3 + 2]));
		}
	}

	return true;
}
示例#15
0
/**
 * When user choose a data source, validate it first, 
 * then create a Project() that will be used by the 
 * main program.
 */
void ExportDataDlg::OnOkClick( wxCommandEvent& event )
{
    int datasource_type = m_ds_notebook->GetSelection();
    IDataSource* datasource = GetDatasource();
    wxString ds_name = datasource->GetOGRConnectStr();
	GdaConst::DataSourceType ds_type = datasource->GetType();
    
    if (ds_name.length() <= 0 ) {
        wxMessageDialog dlg(this, "Please specify a valid data source name.",
                            "Warning", wxOK | wxICON_WARNING);
        dlg.ShowModal();
        return;
    }
    
    bool is_update = false;
    wxString tmp_ds_name;
    
	try{
        TableInterface* table = NULL;
		OGRSpatialReference* spatial_ref = NULL;
        
        if ( project_p == NULL ) {
            //project does not exist, could be created a datasource from
            //geometries only, e.g. boundray file
        } else {
            //case: save current open datasource as a new datasource
			table = project_p->GetTableInt();
			spatial_ref = project_p->GetSpatialReference();
            // warning if saveas not compaptible
            GdaConst::DataSourceType o_ds_type = project_p->GetDatasourceType();
            bool o_ds_table_only = IDataSource::IsTableOnly(o_ds_type);
            bool n_ds_table_only = IDataSource::IsTableOnly(ds_type);
            
            if (o_ds_table_only && !n_ds_table_only) {
                if (project_p && project_p->main_data.records.size() ==0) {
                    if (ds_type == GdaConst::ds_geo_json ||
                        ds_type == GdaConst::ds_kml ||
                        ds_type == GdaConst::ds_shapefile) {
                        // can't save a table-only ds to non-table-only ds,
                        // if there is no new geometries to be saved.
                        wxString msg = "GeoDa can't export a Table-only data "
                        "source to a Geometry data source. Please try to add a "
                        "geometry layer and then export.";
                        throw GdaException(msg.mb_str());
                    }
                }
            } else if ( !o_ds_table_only && n_ds_table_only) {
                // possible loss geom data save a non-table ds to table-only ds
                wxString msg = "The geometries will not be saved when exporting "
                "a Geometry data source to a Table-only data source.\n\n"
                "Do you want to continue?";
                wxMessageDialog dlg(this, msg, "Warning: loss data",
                                    wxYES_NO | wxICON_WARNING);
                if (dlg.ShowModal() != wxID_YES)
                    return;
            }
		}

		// by default the datasource will be re-created, except for some special
        // cases: e.g. sqlite, ESRI FileGDB
		if (datasource_type == 0) {
			if (wxFileExists(ds_name)) {
				if (ds_name.EndsWith(".sqlite")) {
					// add new layer to existing sqlite
					is_update = true;
				} else {
					wxRemoveFile(ds_name);
				}
			} else if (wxDirExists(ds_name)) {
				// only for adding new layer to ESRI File Geodatabase
				is_update = true;
				wxDir dir(ds_name);
				wxString first_filename;
				if (!dir.GetFirst(&first_filename)) {
					// for an empty .gdb directory, create a new FileGDB datasource
					is_update = false;
					wxRmDir(ds_name);
				}
			}
		}

        if( !CreateOGRLayer(ds_name, table, spatial_ref, is_update) ) {
            wxString msg = "Exporting has been cancelled.";
            throw GdaException(msg.mb_str(), GdaException::NORMAL);
        }
        // save project file
        if (m_chk_create_project->IsChecked() ) {
            //wxString proj_fname = project_file_name;
            wxString proj_fname = wxEmptyString;
            ProjectConfiguration* project_conf = NULL;
            
            if ( m_chk_create_project->IsChecked() ){
                // Export case: create a project file
                // Export means exporting current datasource to a new one, and
                // create a new project file that is based on this datasource.
                // E.g. export a shape file to PostgreGIS layer, then the new
                // project file should has <datasource> content of database
                // configuration
                wxString file_dlg_title = "GeoDa Project to Save As";
                wxString file_dlg_type =  "GeoDa Project (*.gda)|*.gda";
                wxFileDialog dlg(this, file_dlg_title, wxEmptyString,
                                 wxEmptyString, file_dlg_type,
                                 wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
                if (dlg.ShowModal() != wxID_OK) return;
                wxFileName f(dlg.GetPath());
                f.SetExt("gda");
                proj_fname = f.GetFullPath();
                // copy a project_conf for exporting, will be deleted later
                project_conf = project_p->GetProjectConf()->Clone();
            }
            // save project file
            wxFileName new_proj_fname(proj_fname);
            wxString proj_title = new_proj_fname.GetName();
            LayerConfiguration* layer_conf
                = project_conf->GetLayerConfiguration();
            layer_conf->SetName(layer_name);
            layer_conf->UpdateDataSource(datasource);
            project_conf->Save(proj_fname);
          
            // in export case, delete cloned project_conf
            if ( proj_fname.empty() ) {
                delete project_conf;
                //delete datasource; Note: it is deleted in project_conf
            }
        }
	} catch (GdaException& e) {
        if (e.type() == GdaException::NORMAL)
            return;
        // special clean up for file datasource
        if ( !tmp_ds_name.empty() ) {
            if ( wxFileExists(tmp_ds_name) && !tmp_ds_name.EndsWith(".sqlite")){
                wxRemoveFile(ds_name);
                wxCopyFile(tmp_ds_name, ds_name);
                wxRemoveFile(tmp_ds_name);
            }
        }
		wxMessageDialog dlg(this, e.what() , "Error", wxOK | wxICON_ERROR);
		dlg.ShowModal();
		return;
	}

	wxString msg = "Export successfully.";
    //msg << "\n\nTips: if you want to use exported project/datasource, please"
    //    << " close current project and then open exported project/datasource.";
	wxMessageDialog dlg(this, msg , "Info", wxOK | wxICON_INFORMATION);
    dlg.ShowModal();
    
	EndDialog(wxID_OK);
}
示例#16
0
ProjectInfoDlg::ProjectInfoDlg(Project* project)
: wxDialog(NULL, wxID_ANY, "Project Information", wxDefaultPosition, wxSize(250, 150))
{
    wxLogMessage("Open ProjectInfoDlg.");
    
	using namespace std;
	wxPanel* panel = new wxPanel(this, -1);
	
	wxBoxSizer* vbox = new wxBoxSizer(wxVERTICAL);
	wxBoxSizer* hbox = new wxBoxSizer(wxHORIZONTAL);
	
	
	vector<wxString> key;
	vector<wxString> val;
	key.push_back("Project Title");
	val.push_back(project->GetProjectTitle());
	
	key.push_back("Project File");
	wxString pfp = project->GetProjectFullPath();
	if (pfp.IsEmpty()) {
		val.push_back("N/A");
	} else {
		val.push_back(pfp);
	}
		
	IDataSource* ds = project->GetDataSource();
	
	key.push_back("Data Source Type");
	val.push_back(GdaConst::datasrc_type_to_str[ds->GetType()]);
	
	if (FileDataSource* d = dynamic_cast<FileDataSource*>(ds)) {
		key.push_back("Data Source File");
		val.push_back(d->GetFilePath());
	} else if (DBDataSource* d = dynamic_cast<DBDataSource*>(ds)) {
		key.push_back("Database Name");
		val.push_back(d->GetDBName());
		key.push_back("Database Host");
		val.push_back(d->GetDBHost());
		key.push_back("Database Port");
		val.push_back(d->GetDBPort());
		key.push_back("Database User");
		val.push_back(d->GetDBUser());
	} else if (WebServiceDataSource* d =
			   dynamic_cast<WebServiceDataSource*>(ds)) {
		key.push_back("Web File Service URL");
		val.push_back(d->GetURL());
	}
	
	key.push_back("Layer Name");
	wxString layername;
	if (ProjectConfiguration* pc = project->GetProjectConf()) {
		if (LayerConfiguration* lc = pc->GetLayerConfiguration()) {
			layername = lc->GetName();
		}
	}
	val.push_back(layername);
	
	TableInterface* table_int = project->GetTableInt();
	key.push_back("Number Records/Observations");
	val.push_back(wxString::Format("%d", table_int->GetNumberRows()));
	
	int table_cols = table_int->GetNumberCols();
	int grp_cnt = 0;
	int fld_cnt = 0;
	int plhdr_cnt = 0;
	for (int c=0; c<table_cols; ++c) {
		if (table_int->IsColTimeVariant(c)) {
			++grp_cnt;
			for (int t=0, ts=table_int->GetColTimeSteps(c); t<ts; ++t) {
				if (table_int->GetColType(c,t) != GdaConst::placeholder_type) {
					++fld_cnt;
				} else {
					++plhdr_cnt;
				}
			}
		} else {
			++fld_cnt;
		}
	}
	
	key.push_back("Number Data Source Fields");
	val.push_back(wxString::Format("%d", fld_cnt));
	
	key.push_back("Number Table Columns");
	val.push_back(wxString::Format("%d", table_cols));
	
	key.push_back("Number Table Groups");
	val.push_back(wxString::Format("%d", grp_cnt));
    
    if (project->IsTableOnlyProject() == false) {
        key.push_back("Map boundary");
        double minx = 0, miny = 0,  maxx = 0,  maxy = 0;
        project->GetMapExtent(minx, miny, maxx, maxy);
        val.push_back(wxString::Format("Lower left: %f, %f Upper right: %f, %f", minx, miny, maxx, maxy));
    }
		
	const int left_offset = 0;
	const int top_offset = 0;
	const int line_space = 25;
	for (int i=0, sz=key.size(); i<sz; ++i) {
		wxString s;
		s << key[i] << ": " << val[i];
		wxStaticText* st;
		wxPoint pos(left_offset, top_offset + i*line_space);
		st = new wxStaticText(panel, wxID_ANY, s, pos, wxDefaultSize, wxALIGN_LEFT);
	}
	
	
	wxButton* ok_btn = new wxButton(this, wxID_OK, "OK", wxDefaultPosition,
									wxDefaultSize, wxBU_EXACTFIT);
	
	hbox->Add(ok_btn, 1, wxLEFT, 15);
	
	vbox->Add(panel, 1, wxALL, 15);
	vbox->Add(hbox, 0, wxALIGN_CENTER | wxALL, 10);
	
	SetSizer(vbox);
	vbox->Fit(this);
	
	Center();
}