How to insert a Path in between an existing Path - graphhopper

I am working on an implementation to generate alternate Paths using via node method.
While checking for local optimality I do the following
forwardEdge = bestWeightMapFrom.get(viaNode);
reverseEdge = bestWeightMapTo.get(viaNode);
double unpackedUntilDistance = 0;
while(forwardEdge.edge != -1) {
double parentDist = forwardEdge.parent != null ? forwardEdge.parent.distance : 0;
double dist = forwardEdge.distance - parentDist;
if(unpackedUntilDistance + dist >= T_THRESHOLD) {
EdgeSkipIterState edgeState = (EdgeSkipIterState) graph.getEdgeProps(forwardEdge.edge, forwardEdge.adjNode);
unpackStack.add(new EdgePair(edgeState, false));
sV = forwardEdge.adjNode;
forwardEdge = forwardEdge.parent;
break;
}
else {
unpackedUntilDistance += dist;
forwardEdge = forwardEdge.parent;
sV = forwardEdge.adjNode;
}
}
int oldSV = forwardEdge.adjNode;
EdgeEntry oldForwardEdge = forwardEdge;
I unpack the edge in the stack to further narrow down sV.
I get vT and oldVt in a similar fashion by traversing reverseEdge.
if I determine that the path from sV and vT is <= length of unpacked edges I accept this via node and construct the alternatePath as follows.
PathBidirRef p = (PathBidirRef) algo.calcPath(oldSV, oldVT);
Path4CHAlt p1 = new Path4CHAlt(graph, flagEncoder);
p1.setSwitchToFrom(false);
p1.setEdgeEntry(oldForwardEdge);
p1.segmentEdgeEntry = p.edgeEntry;
double weight = oldForwardEdge.weight + oldReverseEdge.weight + p.edgeEntry.weight + p.edgeTo.weight;
p1.setWeight(weight);
p1.edgeTo = oldReverseEdge;
p1.segmentEdgeTo = p.edgeTo;
Path p2 = p1.extract();
Path4CHAlt is
public class Path4CHAlt extends Path4CH {
private boolean switchWrapper = false;
public EdgeEntry segmentEdgeTo;
public EdgeEntry segmentEdgeEntry;
public Path4CHAlt( Graph g, FlagEncoder encoder )
{
super(g, encoder);
}
public Path4CHAlt setSwitchToFrom( boolean b )
{
switchWrapper = b;
return this;
}
#Override
public Path extract()
{
System.out.println("Path4CHAlt extract");
if (edgeEntry == null || edgeTo == null || segmentEdgeEntry == null || segmentEdgeTo == null)
return this;
if (switchWrapper)
{
EdgeEntry ee = edgeEntry;
edgeEntry = edgeTo;
edgeTo = ee;
ee = segmentEdgeEntry;
segmentEdgeEntry = segmentEdgeTo;
segmentEdgeTo = ee;
}
EdgeEntry currEdge = segmentEdgeEntry;
while (EdgeIterator.Edge.isValid(currEdge.edge))
{
processEdge(currEdge.edge, currEdge.adjNode);
currEdge = currEdge.parent;
}
currEdge.parent = edgeEntry;
currEdge = edgeEntry;
while (EdgeIterator.Edge.isValid(currEdge.edge))
{
processEdge(currEdge.edge, currEdge.adjNode);
currEdge = currEdge.parent;
}
setFromNode(currEdge.adjNode);
reverseOrder();
currEdge = segmentEdgeTo;
int tmpEdge = currEdge.edge;
while (EdgeIterator.Edge.isValid(tmpEdge))
{
currEdge = currEdge.parent;
processEdge(tmpEdge, currEdge.adjNode);
tmpEdge = currEdge.edge;
}
currEdge.parent = edgeTo;
currEdge = edgeTo;
tmpEdge = currEdge.edge;
while (EdgeIterator.Edge.isValid(tmpEdge))
{
currEdge = currEdge.parent;
processEdge(tmpEdge, currEdge.adjNode);
tmpEdge = currEdge.edge;
}
setEndNode(currEdge.adjNode);
return setFound(true);
}
}
This is not working all the time. I get exceptions in Path4CH
java.lang.NullPointerException
at com.graphhopper.routing.ch.Path4CH.expandEdge(Path4CH.java:62)
at com.graphhopper.routing.ch.Path4CH.processEdge(Path4CH.java:56)
at com.graphhopper.routing.PathBidirRef.extract(PathBidirRef.java:95)
at com.graphhopper.routing.DijkstraBidirectionRef.extractPath(DijkstraBidirectionRef.java:99)
at com.graphhopper.routing.AbstractBidirAlgo.runAlgo(AbstractBidirAlgo.java:74)
at com.graphhopper.routing.AbstractBidirAlgo.calcPath(AbstractBidirAlgo.java:60)
In Path
java.lang.IllegalStateException: Edge 1506012 was empty when requested with node 1289685, array index:0, edges:318
at com.graphhopper.routing.Path.forEveryEdge(Path.java:253)
at com.graphhopper.routing.Path.calcInstructions(Path.java:349)
I dont know what I am doing wrong. I could really use some help with this.
Thanks.

I solved this issue.
Inside DijkstraBidirectionRef.calcPath I was trying to calculate shortest path from an arbitrary node to source node and vertex node.
The error used to occur because the original call to calcPath was operating on QueryGraph and inside I was creating a new Object of DijkstraBidirectionRef using LevelGraphStorage.
This was a problem because QueryGraph may create virtual nodes and edges for source and target nodes. Call to calcPath(node, virtualNode) operating on LevelGraphStorage would throw an exception.
The fix was to call algo.setGraph(queryGraph) after creating DijkstraBidirectionRef.

Related

Json data serialized with JsonConvert.SerializeObject is always string in ASP.NET Web API

I am developing a ASP.NET MVC Web Api. Project. I am returning data with JSON format. Before I return data to user I serialize data using JsonConvert.SerializeObject to change their json property names.My code return data in JSON format. But with an issue. That is it always return data into string even if the data is array or object.
This is my action method that returns json.
public HttpResponseMessage Get()
{
IEnumerable<Region> dbRegions = regionRepo.GetCachedRegions();
List<ContentRegion> regions = new List<ContentRegion>();
if(dbRegions!=null && dbRegions.Count()>0)
{
foreach(var region in dbRegions)
{
ContentRegion contentRegion = new ContentRegion
{
Id = region.Id,
ImageUrl = Url.AbsoluteContent(region.ImagePath),
SmallImageUrl = (String.IsNullOrEmpty(region.ImagePath))?null:Url.AbsoluteContent(CommonHelper.GetImageUrl(region.ImagePath,AppConfig.SmallThumbSuffix)),
MediumImageUrl = (String.IsNullOrEmpty(region.ImagePath))?null:Url.AbsoluteContent(CommonHelper.GetImageUrl(region.ImagePath,AppConfig.MediumThumbSuffix)),
Name = region.Name,
MmName = region.MmName,
Description = region.Description,
MmDescription = region.MmDescription,
Latitude = region.Latitude,
Longitude = region.Longitude
};
regions.Add(contentRegion);
}
}
string json = JsonConvert.SerializeObject(regions);
if(!string.IsNullOrEmpty(json))
{
json = json.Trim(new char[] { '"' });
}
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ObjectContent(json.GetType(),json,Configuration.Formatters.JsonFormatter)
};
}
Actually this code should return Json array. But when I parse data from client (from Android using Volley). It cannot be parsed into Json Array.
This is the data I get:
As you can see the double quote both in the beginning and at the end. The reason I cannot parse it into array in Volley is it is returning as a string because of that double. How can I serialize it trimming that quote? I used trim, but not removed.
You are unnecessarily complicating things. In Web API you can return JSON just by returning any object inside the built-in methods, the framework will serialize it for you.
public IHttpActionResult Get()
{
IEnumerable<Region> dbRegions = regionRepo.GetCachedRegions();
List<ContentRegion> regions = new List<ContentRegion>();
if(dbRegions != null && dbRegions.Count() > 0) {
foreach(var region in dbRegions)
{
ContentRegion contentRegion = new ContentRegion
{
Id = region.Id,
ImageUrl = Url.AbsoluteContent(region.ImagePath),
SmallImageUrl = (String.IsNullOrEmpty(region.ImagePath))?null:Url.AbsoluteContent(CommonHelper.GetImageUrl(region.ImagePath,AppConfig.SmallThumbSuffix)),
MediumImageUrl = (String.IsNullOrEmpty(region.ImagePath))?null:Url.AbsoluteContent(CommonHelper.GetImageUrl(region.ImagePath,AppConfig.MediumThumbSuffix)),
Name = region.Name,
MmName = region.MmName,
Description = region.Description,
MmDescription = region.MmDescription,
Latitude = region.Latitude,
Longitude = region.Longitude
};
regions.Add(contentRegion);
}
}
return Ok(regions);
}
As an aside: from what I can see you are mapping manually your domain objects into DTOs: take into consideration the use of an automatic mapping mechanism like AutoMapper.
I am not sure this is the best solution or not. I solved the problem using this way.
This is my action method
public HttpResponseMessage Get()
{
try
{
IEnumerable<Region> dbRegions = regionRepo.GetCachedRegions();
List<ContentRegion> regions = new List<ContentRegion>();
if (dbRegions != null && dbRegions.Count() > 0)
{
foreach (var region in dbRegions)
{
ContentRegion contentRegion = new ContentRegion
{
Id = region.Id,
ImageUrl = Url.AbsoluteContent(region.ImagePath),
SmallImageUrl = (String.IsNullOrEmpty(region.ImagePath)) ? null : Url.AbsoluteContent(CommonHelper.GetImageUrl(region.ImagePath, AppConfig.SmallThumbSuffix)),
MediumImageUrl = (String.IsNullOrEmpty(region.ImagePath)) ? null : Url.AbsoluteContent(CommonHelper.GetImageUrl(region.ImagePath, AppConfig.MediumThumbSuffix)),
Name = region.Name,
MmName = region.MmName,
Description = region.Description,
MmDescription = region.MmDescription,
Latitude = region.Latitude,
Longitude = region.Longitude
};
regions.Add(contentRegion);
}
}
string json = JsonConvert.SerializeObject(regions);
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(json, Encoding.Default, "application/json")
};
}
catch
{
return Request.CreateResponse(HttpStatusCode.InternalServerError);
}
}
It's not required to convert object to json string.
You can try :
return Request.CreateResponse<List<ContentRegion>>(HttpStatusCode.OK,regions);
Not tested.
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
Use this line in your WebApiConfig.
And here your code should be
public HttpResponseMessage Get()
{
IEnumerable<Region> dbRegions = regionRepo.GetCachedRegions();
List<ContentRegion> regions = new List<ContentRegion>();
HttpResponseMessage temp = ControllerContext.Request.CreateResponse(HttpStatusCode.OK, "");
if (dbRegions != null && dbRegions.Count() > 0)
{
foreach (var region in dbRegions)
{
ContentRegion contentRegion = new ContentRegion
{
Id = region.Id,
ImageUrl = Url.AbsoluteContent(region.ImagePath),
SmallImageUrl = (String.IsNullOrEmpty(region.ImagePath)) ? null : Url.AbsoluteContent(CommonHelper.GetImageUrl(region.ImagePath, AppConfig.SmallThumbSuffix)),
MediumImageUrl = (String.IsNullOrEmpty(region.ImagePath)) ? null : Url.AbsoluteContent(CommonHelper.GetImageUrl(region.ImagePath, AppConfig.MediumThumbSuffix)),
Name = region.Name,
MmName = region.MmName,
Description = region.Description,
MmDescription = region.MmDescription,
Latitude = region.Latitude,
Longitude = region.Longitude
};
regions.Add(contentRegion);
}
}
temp = ControllerContext.Request.CreateResponse(HttpStatusCode.OK, regions);
return temp;
//string json = JsonConvert.SerializeObject(regions);
//if (!string.IsNullOrEmpty(json))
//{
// json = json.Trim(new char[] { '"' });
//}
//return new HttpResponseMessage(HttpStatusCode.OK)
//{
// Content = new ObjectContent(json.GetType(), json, Configuration.Formatters.JsonFormatter)
//};
}

How to differentiate pdf document types with PDFSharp?

There are basically 4 types of pdf files.
• PDF Image Only
• PDF Searchable Image Exact
• PDF Searchable Image Compact
• PDF Formatted Text and Graphics
I need to know how to differentiate a given pdf document in-order to perform OCR.
I've tried something like this, but the given pdf which identified as Image only (mentioned as Scanned in my code) failed to be converted as an image using Image.fromStream method.
public static PdfType GetPdfType(Stream sourcePdf)
{
PdfDocument pdf = PdfReader.Open(sourcePdf);
PdfDictionary pg = pdf.Pages[0];
PdfDictionary res = pg.Elements.GetDictionary("/Resources");
PdfDictionary xobj = res.Elements.GetDictionary("/XObject");
PdfDictionary font = res.Elements.GetDictionary("/Font");
if (xobj == null)
{
return PdfType.Text;
}
else if (xobj != null && font != null)
{
return PdfType.ScannedText;
}
else
return PdfType.Scanned;
}
Edit: Here is the code snippet where I try to add images which are extracted from pdf file
public static Collection<Image> GetExtractedImagesFromPDF(Stream sourcePdf, string outputPath)
{
Collection<Image> extractedImages = new Collection<Image>();
PdfDocument pdf = PdfReader.Open(sourcePdf);
for (int pageNumber = 0; pageNumber < pdf.Pages.Count; pageNumber++)
{
PdfDictionary pg = pdf.Pages[pageNumber];
// recursively search pages, forms and groups for images.
PdfDictionary obj = FindImageInPDFDictionary(pg);
if (obj != null)
{
byte[] bytes = obj.Stream.Value;
ImageConverter ic = new ImageConverter();
//Image img = (Image)ic.ConvertFrom(bytes); // throws parameter not valid error
MemoryStream ms = new MemoryStream(bytes);
Image img = Image.FromStream(ms, false, true); // throws parameter not valid error
extractedImages.Add(img);
}
}
return extractedImages;
}
And this is the FindImageInPdfDictionary method
static PdfDictionary FindImageInPDFDictionary(PdfDictionary pg)
{
PdfDictionary res = pg.Elements.GetDictionary("/Resources");
if (res != null)
{
PdfDictionary xobj = res.Elements.GetDictionary("/XObject");
if (xobj != null)
{
ICollection<PdfItem> items = xobj.Elements.Values;
foreach (PdfItem item in items)
{
PdfReference reference = item as PdfReference;
if (reference != null)
{
PdfDictionary xObject = reference.Value as PdfDictionary;
if (xObject != null && xObject.Elements.GetString("/Subtype") == "/Image")
{
return xObject;
}
}
}
}
}
return null;
}

APEX, Unit Test, Callout No Response with Static Resource

Bit stuck on another one i'm afraid, i am trying to write a unit test for a bulk APEX class.
The class has a calllout to the google api, so i have created a static resource which i am feeding in via a mock, so i can complete testing of processing the JSON that is returned. However for some reason the response is always empty.
Now the very odd thing is that if i use exactly the same callout/JSON code, and the same mock code on a previous #future call, then it does return fine.
Here is the class:
global class mileage_bulk implements Database.Batchable<sObject>,
Database.AllowsCallouts
{
global Database.QueryLocator start(Database.BatchableContext BC)
{
String query = 'SELECT Id,Name,Amount,R2_Job_Ref__c,R2_Shipping_Post_Code__c,Shipping_Postcode_2__c FROM Opportunity WHERE R2_Shipping_Post_Code__c != null';
return Database.getQueryLocator(query);
//system.debug('Executing'+query);
}
global void execute(Database.BatchableContext BC, List<Opportunity> scope)
{
system.debug(scope);
for(Opportunity a : scope)
{
String startPostcode = null;
startPostcode = EncodingUtil.urlEncode('HP27DU', 'UTF-8');
String endPostcode = null;
String endPostcodeEncoded = null;
if (a.R2_Shipping_Post_Code__c != null){
endPostcode = a.R2_Shipping_Post_Code__c;
Pattern nonWordChar = Pattern.compile('[^\\w]');
endPostcode = nonWordChar.matcher(endPostcode).replaceAll('');
endPostcodeEncoded = EncodingUtil.urlEncode(endPostcode, 'UTF-8');
}
Double totalDistanceMeter = null;
Integer totalDistanceMile = null;
String responseBody = null;
Boolean firstRecord = false;
String ukPrefix = 'UKH';
if (a.R2_Job_Ref__c != null){
if ((a.R2_Job_Ref__c).toLowerCase().contains(ukPrefix.toLowerCase())){
system.debug('Is Hemel Job');
startPostcode = EncodingUtil.urlEncode('HP27DU', 'UTF-8');
} else {
system.debug('Is Bromsgrove Job');
startPostcode = EncodingUtil.urlEncode('B604AD', 'UTF-8');
}
}
// build callout
Http h = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint('http://maps.googleapis.com/maps/api/directions/json?origin='+startPostcode+'&destination='+endPostcodeEncoded+'&units=imperial&sensor=false');
req.setMethod('GET');
req.setTimeout(60000);
system.debug('request follows');
system.debug(req);
try{
// callout
HttpResponse res = h.send(req);
// parse coordinates from response
JSONParser parser = JSON.createParser(res.getBody());
responseBody = res.getBody();
system.debug(responseBody);
while (parser.nextToken() != null) {
if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) &&
(parser.getText() == 'distance')){
parser.nextToken(); // object start
while (parser.nextToken() != JSONToken.END_OBJECT){
String txt = parser.getText();
parser.nextToken();
//system.debug(parser.nextToken());
//system.debug(txt);
if (firstRecord == false){
//if (txt == 'text'){
//totalDistanceMile = parser.getText();
system.debug(parser.getText());
//}
if (txt == 'value'){
totalDistanceMeter = parser.getDoubleValue();
double inches = totalDistanceMeter*39.3701;
totalDistanceMile = (integer)inches/63360;
system.debug(parser.getText());
firstRecord = true;
}
}
}
}
}
} catch (Exception e) {
}
//system.debug(accountId);
system.debug(a);
system.debug(endPostcodeEncoded);
system.debug(totalDistanceMeter);
system.debug(totalDistanceMile);
// update coordinates if we get back
if (totalDistanceMile != null){
system.debug('Entering Function to Update Object');
a.DistanceM__c = totalDistanceMile;
a.Shipping_Postcode_2__c = a.R2_Shipping_Post_Code__c;
//update a;
}
}
update scope;
}
global void finish(Database.BatchableContext BC)
{
}
}
and here is the test class;
#isTest
private class mileage_bulk_tests{
static testMethod void myUnitTest() {
Opportunity opp1 = new Opportunity(name = 'Google Test Opportunity',R2_Job_Ref__c = 'UKH12345',R2_Shipping_Post_Code__c = 'AL35QW',StageName = 'qualified',CloseDate = Date.today());
insert opp1;
Opportunity opp2 = new Opportunity(name = 'Google Test Opportunity 2',StageName = 'qualified',CloseDate = Date.today());
insert opp2;
Opportunity opp3 = new Opportunity(name = 'Google Test Opportunity 3',R2_Job_Ref__c = 'UKB56789',R2_Shipping_Post_Code__c = 'AL35QW',StageName = 'qualified',CloseDate = Date.today());
insert opp3;
StaticResourceCalloutMock mock = new StaticResourceCalloutMock();
mock.setStaticResource('googleMapsJSON');
mock.setStatusCode(200); // Or other appropriate HTTP status code
mock.setHeader('Content-Type', 'application/json'); // Or other appropriate MIME type like application/xml
//Set the mock callout mode
Test.setMock(HttpCalloutMock.class, mock);
system.debug(opp1);
system.debug(opp1.id);
//Call the method that performs the callout
Test.startTest();
mileage_bulk b = new mileage_bulk();
database.executeBatch((b), 10);
Test.stopTest();
}
}
Help greatly appreciated!
Thanks
Gareth
Not certain what 'googleMapsJSON' looks like, perhaps you could post for us.
Assuming your mock resource is well formatted, make sure the file extension is ".json" and was saved with UTF-8 encoding.
If #2 does not work, you should try saving your resource as .txt - I've run in to this before where it needed a plain text resource but expected application/json content type
Be certain that the resource name string you are providing has the same casing as the name of the resource. It is case sensitive.
Are you developing on a namespaced package environment? Try adding the namespace to the resource name if so.
Otherwise, your code looks pretty good at first glance.

How to fix the lambda expression delegate error?

I am using this method to get data
private void getNews(int cat_id, int page)
{
this.progress.Visibility = Visibility.Visible;
var m = new SharpGIS.GZipWebClient();
Microsoft.Phone.Reactive.Observable.FromEvent<DownloadStringCompletedEventArgs>(m, "DownloadStringCompleted").Subscribe(l =>
{
try
{
//List<NewsKeys> deserialized = JsonConvert.DeserializeObject<List<NewsKeys>>(r.EventArgs.Result);
ObservableCollection<NewsKeys> deserialized = JsonConvert.DeserializeObject<List<NewsKeys>>(l.EventArgs.Result);
foreach (NewsKeys item in deserialized)
{
items.Add(new NewsKeys { nId = item.nId, title = item.title, shortDesc = item.shortDesc, fullDesc = item.fullDesc, tags = item.tags, smallPic = item.smallPic, bigPic = item.bigPic, video = item.video, audio = item.audio, youtube = item.youtube, doc = item.doc, date_create = item.date_create, date_modify = item.date_modify, date_publish = item.date_publish, catId = item.catId, viewOrder = item.viewOrder, viewCount = item.viewCount, viewStatus = item.viewStatus, viewHome = item.viewHome, uId = item.uId, uFname = item.uFname });
}
}
catch (Exception)
{
MessageBox.Show("Sorry, Some unexpected error.");
}
});
m.DownloadStringAsync(new Uri(Resource.NEWS_API+cat_id+"&page="+page));
}
The error i get is
Error 1 Cannot convert lambda expression to type 'System.IObserver>' because it is not a delegate type C:\Users\Adodis\Documents\Visual Studio 2010\Projects\TV\NewsListPage.xaml.cs 51 133
I have tried all the fixes but unable to fix this problem. Am using the same block in different method in a different class it is working fine but, this method in this class killing me. Please help me if you have idea on this.
Thanks in advance.
Try this (I've separated the Select and Subscribe operations):
var m = new SharpGIS.GZipWebClient();
Observable.FromEvent<DownloadStringCompletedEventArgs>(m, "DownloadStringCompleted")
.Select(l => l.EventArgs.Result)
.Subscribe(res =>
{
try
{
var deserialized = JsonConvert.DeserializeObject<List<NewsKeys>>(res);
foreach (NewsKeys item in deserialized)
{
items.Add(
new NewsKeys
{
nId = item.nId,
title = item.title,
shortDesc = item.shortDesc,
fullDesc = item.fullDesc,
tags = item.tags,
smallPic = item.smallPic,
bigPic = item.bigPic,
video = item.video,
audio = item.audio,
youtube = item.youtube,
doc = item.doc,
date_create = item.date_create,
date_modify = item.date_modify,
date_publish = item.date_publish,
catId = item.catId,
viewOrder = item.viewOrder,
viewCount = item.viewCount,
viewStatus = item.viewStatus,
viewHome = item.viewHome,
uId = item.uId,
uFname = item.uFname
});
}
}
catch (Exception)
{
MessageBox.Show("Sorry, Some unexpected error.");
}
});
m.DownloadStringAsync(new Uri("Resource.NEWS_API" + cat_id + "&page=" + page));

Use Rave with MyDac

I'm using Cbuilder XE and I want to use Rave Report with Mydac component but it seems to me that Rave recognize only the standard TQuery component and ignore the Mydac versions.
I would ask you if there is a way to feed a Rave report using TMyQuery component and possiby, a simple example which print a plain list of the result of such query.
I only know how to do this in Delphi, so you will have to translate it to CBuilder equivalents. I am pretty sure that Delphi and CBuilder are identical with respect to RAVE components. I don't know how to do this programmatically, but it is relatively easy using the RAVE report designer.
I use RAVE TRvDataSetConnection components to link TMyQuery components to reports.
You typically drop TRvDataSetConnection components on your datamodule, along with your queries - one TRvDataSetConnection per TMyQuery. You have to add all the SQL fields to your TMyQuery components to make the field names show up in the report designer. You can do this automatically by opening the Field Editor for a TMyQuery and hitting ^F. If you have a valid connection to your MySQL server then the fields will fill in and be assigned the proper data types.
Next, inside the RAVE report designer you create a New Data Object and select the Direct Data View item. Connect the DataView to the RvDataSetConnections in your datamodule. Now you can access all the fields to the TMyQuery. You link the DataView in the RAVE Designer to the report band you want to display the query contents in.
Plan B is to buy and install FastReports. RAVE is pretty bad :-)
MY own way to use Rave as generic print utility
void __fastcall TFormMain::Action_ReportExecute(TObject * Sender)
{
__try
{
Screen->Cursor = crHourGlass;
int maxrow = 0;
RvSystem1->Execute();
}
__finally
{
Screen->Cursor = crDefault;
}
}
RvSystem1Print : is the event onPrint of a RvSystem component
I can't be able to build it at run-time so I have to add a component for each form where I need the print utility
void __fastcall TFormMain::RvSystem1Print(TObject * Sender)
{
int maxrow = 0;
String Fun = "[FormMain::RvSystem1Prin] ";
try
{
RvSystem1->SystemPreview->FormWidth = ( Screen->Width > 900 ) ? 900 : Screen->Width ;
RvSystem1->SystemPreview->FormHeight = Screen->Height * 0.9;
TBaseReport * report = (TBaseReport*) Sender;
UtilClientPmv::DBGridToRaveReport(DBGrid1, report, maxrow);
}
catch (Exception & ex)
{
Mylog(Fun + Sysutils::Format("ERROR=[%s] ", ARRAYOFCONST((ex.Message))));
}
}
DBGridToRaveReport: scan and print all record in a table linked to a dbgrid ( included images )
int __fastcall UtilClientPmv::DBGridToRaveReport(TDBGrid * grid, TBaseReport * report, int maxrow)
{
String Fun = "[UtilClientPmv::DBGridToRaveReport] ";
TMWTable * mwTable = NULL;
int iret = IRET_OK;
try
{
mwTable = (TMWTable*) grid->DataSource->DataSet;
iret = MWTableToRaveReport(mwTable, report, maxrow);
}
catch (Exception & ex)
{
Util::mylog(Fun + Sysutils::Format("ERROR=[%s] ", ARRAYOFCONST((ex.Message))));
}
return iret;
}
MWTableToRaveReport: scan and print all record in a table ( included images )
int __fastcall UtilClientPmv::MWTableToRaveReport(TMWTable * mwTable, TBaseReport * report, int maxrow)
{
String fldName, fldValue, smsg, Fun = "[UtilClientPmv::MWTableToRaveReport] ";
int tot_row, tot_fld, tot_rec, iret = IRET_OK;
double x, y, y2, rpos, pgWidth;
TField * fld = NULL;
TBookmark bkMark; // TBookmark == TByteDynArray
Graphics::TBitmap * bitmap = NULL;
try
{
if (maxrow == 0)
{
maxrow = 1000;
}
__try
{
if (mwTable->Active == false)
{
mwTable->Active = true;
}
tot_row = mwTable->Data->RecordCount;
if (tot_row < 0)
{
throw Exception("RecordCount in Null");
}
if (tot_row > maxrow)
{
tot_row = maxrow;
}
report->StatusFormat = "Page %d";
report->Units = unMM;
pgWidth = report->PageWidth;
mwTable->DisableControls();
bkMark = mwTable->GetBookmark();
tot_fld = mwTable->FieldCount;
tot_rec = mwTable->RecordCount;
int irow = 1, icol;
mwTable->First();
report->SetFont("Courier New", 10);
report->PrintCenter("Report PmvManager", pgWidth / 2);
report->NewLine();
report->SetTab(10, pjLeft, 160, 0, 0, 0);
while (!mwTable->Eof)
{
smsg = Sysutils::Format("Record %03d / %03d", ARRAYOFCONST((irow, tot_row)));
report->PrintTab(smsg);
report->NewLine();
for (int icol = 0; icol < tot_fld; icol++)
{
String NumberFormat, strValue;
fld = mwTable->Fields->Fields[icol];
fldName = fld->DisplayName;
// int lnum = report->LineNum;
int lleft = report->LinesLeft();
if (lleft == 0)
{
report->NewPage();
}
if (fld->DataType == ftBlob)
{
smsg = Sysutils::Format("%30s : ", ARRAYOFCONST((fldName)));
report->PrintTab(smsg);
x = report->XPos;
y = report->YPos;
if (!fld->IsNull)
{
bitmap = new Graphics::TBitmap();
__try
{
TGraphicField * gFld = (TGraphicField*)fld;
if (gFld)
{
TMemoryStream * memStream = new TMemoryStream();
__try
{
gFld->SaveToStream(memStream);
if (memStream->Size > 1)
{
memStream->Seek(0, soFromBeginning);
bitmap->LoadFromStream(memStream);
report->PrintBitmapRect(x, y - 3, x + 12, y + 9, bitmap);
}
report->NewLine();
report->NewLine();
}
__finally
{
delete memStream;
memStream = 0;
}
}
}
__finally
{
delete bitmap;
bitmap = 0;
}
}
}
else
{
fldValue = fld->AsString;
smsg = Sysutils::Format("%30s : %s ", ARRAYOFCONST((fldName, fldValue)));
report->PrintTab(smsg);
}
report->NewLine();
}
irow++;
mwTable->Next();
x = report->XPos;
y = report->YPos;
report->MoveTo(2, y);
report->LineTo(pgWidth - 4, y);
report->MoveTo(x, y);
report->NewLine();
report->NewPara();
}
}
__finally
{
mwTable->GotoBookmark(bkMark);
mwTable->EnableControls();
mwTable->FreeBookmark(bkMark);
}
}
catch (Exception & ex)
{
Util::mylog(Fun + Sysutils::Format("ERROR=[%s] ", ARRAYOFCONST((ex.Message))));
}
return iret;
} // __________ UtilClientPmv::MWTableToRaveReport