Sorting in OpenOffice Calc via Delphi - sorting

I've spent several hours trying to sort data in OpenOffice Calc in Delphi. I tried to follow the examples in basic (from "OpenOffice.org Macros Explained"*) or C#, but still no result. Data wont change at all. What am i doing wrong?
Maybe the problem is with data types?
*https://www.pitonyak.org/OOME_3_0.pdf, page 488.
Minimal reproducible example:
program OpenOfficeCalcSortingIssue;
{$APPTYPE CONSOLE}
uses
System.SysUtils, Variants, ComObj, ActiveX;
var
StarOffice: OleVariant;
SODesktop: OleVariant;
SOCalc: OleVariant;
CalcSheets: OleVariant;
CalcSheet: OleVariant;
SortFields: OleVariant;
SortDescriptor: OleVariant;
begin
CoInitialize(nil);
try
try
StarOffice:=CreateOleObject('com.sun.star.ServiceManager');
SODesktop:=StarOffice.CreateInstance('com.sun.star.frame.Desktop');
SOCalc:=SODesktop.LoadComponentFromURL('private:factory/scalc', '_blank', 0, VarArrayCreate([0, -1], varVariant));
CalcSheets:=SOCalc.GetSheets;
CalcSheet:=CalcSheets.GetByIndex(0);
CalcSheet.GetCellByPosition(0, 0).SetValue(2);
CalcSheet.GetCellByPosition(0, 1).SetValue(1);
CalcSheet.GetCellByPosition(0, 2).SetValue(4);
CalcSheet.GetCellByPosition(0, 3).SetValue(3);
SortFields:=VarArrayCreate([0, 0], varVariant);
SortFields[0]:=StarOffice.Bridge_GetStruct('com.sun.star.util.SortField');
SortFields[0].Field:=0;
SortFields[0].SortAscending:=True;
SortDescriptor:=VarArrayCreate([0, 0], varVariant);
SortDescriptor[0]:=StarOffice.Bridge_GetStruct('com.sun.star.beans.PropertyValue');
SortDescriptor[0].Name:='SortFields';
SortDescriptor[0].Value:=SortFields;
CalcSheet.GetCellRangeByName('A1:A4').Sort(SortDescriptor);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
finally
CoUninitialize;
end;
end.

As usual, solution came shortly after exposing the problem to the world :-) I've found an example from the depths of Internet. Hope this topic on SO will be googled a way more easily by people who stumbled into this issue.
The answer is: SortFields is not just a variants array. It is a "Value Object" and must be set like this:
ValueObject:=StarOffice.Bridge_GetValueObject;
ValueObject.Set('[]com.sun.star.table.TableSortField', SortFields);
In example that i found it is commented "you must specify which type of sequence is transmitted to SortFields property".
So the whole code should be:
StarOffice:=CreateOleObject('com.sun.star.ServiceManager');
SODesktop:=StarOffice.CreateInstance('com.sun.star.frame.Desktop');
SOCalc:=SODesktop.LoadComponentFromURL('private:factory/scalc', '_blank', 0, VarArrayCreate([0, -1], varVariant));
CalcSheets:=SOCalc.GetSheets;
CalcSheet:=CalcSheets.GetByIndex(0);
CalcSheet.GetCellByPosition(0, 0).SetValue(2);
CalcSheet.GetCellByPosition(0, 1).SetValue(1);
CalcSheet.GetCellByPosition(0, 2).SetValue(4);
CalcSheet.GetCellByPosition(0, 3).SetValue(3);
SortFields:=VarArrayCreate([0, 0], varVariant);
SortFields[0]:=StarOffice.Bridge_GetStruct('com.sun.star.table.TableSortField');
SortFields[0].Field:=0;
SortFields[0].IsAscending:=True;
ValueObject:=StarOffice.Bridge_GetValueObject;
ValueObject.Set('[]com.sun.star.table.TableSortField', SortFields);
SortDescriptor:=VarArrayCreate([0, 0], varVariant);
SortDescriptor[0]:=StarOffice.Bridge_GetStruct('com.sun.star.beans.PropertyValue');
SortDescriptor[0].Name:='SortFields';
SortDescriptor[0].Value:=ValueObject;
CalcSheet.GetCellRangeByName('A1:A4').Sort(SortDescriptor);

Related

Pascal exitcode 201 [duplicate]

This question already has an answer here:
How to fix run-time error 201
(1 answer)
Closed 5 years ago.
I am having problems with this program. The project is for it to be a cash register.
Program Cash_Register;
var
ItemsPrices: array[1..20] of real;
ItemsNames: array[1..20] of string;
Item_Number: integer;
NameNumber: integer;
PriceTracker: integer; {1}
NameTracker: integer; {1}
To_End_Or_Not_To_End: string;
PriceNumber: integer; {0}
Subtotal: real;
gst_sum: real;
Final_Total: real;
const
GST: real = 0.125; {0.125}
Base: integer = 21; {21}
CR: string = #13; {#13}
LF: string = #10; {#10}
CRLF: string = #13#10; {CR + LF}
begin
{Variable and constant assignment}
PriceTracker:= 1;
NameTracker:= 1;
PriceNumber:= 0;
{This area below starts the name taking and price taking}
while (PriceTracker AND NameTracker) < Base do
begin
{This area below Asks the user for the name of the product}
Writeln('Please enter the name of product ');
write(Item_Number);
write(' please.');
readln(ItemsNames[Item_Number]);
{This area below asks the user for the price of said item}
Writeln('Please enter the price of product ');
write(Item_Number);
write(' please.');
readln(ItemsPrices[Item_Number]);
{This area below imcrements the counter by 1}
Item_Number:= Item_Number + 1;
{This area below asks the user if they want ot continue or not}
writeln('Do you want to stop entering items? [Yes/No]');
readln(To_End_Or_Not_To_End);
{This area below will determine the programs path}
if To_End_Or_Not_To_End = 'Yes' then
continue
else
break
end;
NameNumber:= Item_Number + 1;
PriceNumber:= Item_Number + 1;
Item_Number:= 1;
{This area below defines the code that will create the Subtotal}
while Item_Number < PriceNumber do
begin
Subtotal:= Subtotal + ItemsPrices[Item_Number];
Item_Number:= Item_Number + 1;
end;
gst_sum:= Subtotal * GST;
Final_Total:= Subtotal + gst;
Item_Number:= 1;
{This area below prints the List of items and prices in reciept form}
while Item_Number < NameNumber do
begin
write(ItemsNames[Item_Number]);
write(' Bz$ ');
write(ItemsPrices[Item_Number]);
write(CRLF);
Item_Number:= Item_Number + 1;
continue
end;
{This area below prints a reciept for the customer}
write('Subtotal'#9#9);
write(Subtotal);
writeln('GST tax 12.5%'#9#9 + 'Bz$');
write(gst_sum);
writeln('Total'#9#9 + 'Bz$');
write(Final_Total);
write(CRLF);
writeln('Tips:______________________________');
writeln(CRLF);
writeln('Total:_____________________________');
writeln(CRLF);
writeln('Print Name:________________________');
writeln(CRLF);
writeln('Signature__________________________');
end.
But it compiled and it throws an error at me saying "excited with exitcode 201." I don't want to change the structure and I have no idea what is going on with the compiler as it refuses to run without immediately exiting. What i'm Trying is to see what happens as it is exiting, because I managed to catch a glimpse of the text that should appear on startup. If someone knows what is wrong, do please inform me.
The cause of your problem is staring you in the face, but I suspect you don't know enough yet to realise what it is.
When these lines execute
Writeln('Please enter the name of product ');
write(Item_Number);
write(' please.');
what you see is
Please enter the name of product
0 please.
This is telling you that the value of Item_Number is 0 (zero). Your next statement is
readln(ItemsNames[Item_Number]);
You've declared your ItemNames array as having elements 1 to 20, so there is no ItemNames[0], which is what your readln is trying to read. Same thing with your
readln(ItemsPrices[Item_Number]);
To fix this, assign the value 1 to Item_Number before your while loop begins.
Next, add the statement
readln();
as the very last line of your program (before the end.). That will stop the console window closing before you have a chance to read what your program outputs.
The above should at least get you started on debugging you program. You'll need to learn how to debug the rest yourself. Google yourself some debugger tutorials, e.g. this one https://www.youtube.com/watch?v=LZ90IBa9_8M
Until you get to grips with debugging your own code, you will get absolutely nowhere in Pascal or any other programming language. Others may disagree, but imo it is probably the single most important skill a programmer needs.

lua - How to perform transitions in sequence

i'm trying to move an object along the points of a complex curved path with a constant velocity using transitions.
I have two tables to keep the coordinates of the points and another table with the respective time intervals for travelling each linear segment at the same speed (despite they have different lengths).
Assuming the firts and last values of the "timeTable" are 0, i tried with something similar to this:
local i = 1
local function Move()
transition.to(player, {time=timeTable[i+1], x=TableX[i+1], y=TableY[i+1]})
i=i+1
end
timer.performWithDelay( timeTable[i], Move, 0 )
It doesn't work although it no error is given.
Thanks in advance for your helpenter code here
May be this would work
local timeTable = {1, 3, 4, 1}
local TableX = {100, 400, 400, 500}
local TableY = {100, 100, 500, 500}
local i = 0
local function onCompleteMove()
i = i + 1
if timeTable[i] then
transition.to(player, {
time=timeTable[i],
x=TableX[i],
y=TableY[i],
onComplete=onCompleteMove
})
end
end
onCompleteMove() -- start moving to first point
Try
Tutorial: Moving objects along a path
Tutorial: Working with curved paths
Method for chain of transition for the same object
local function chainOfTransitions(object, params, ...)
if params then
function params.onComplete()
chainOfTransitions(object, unpack(arg))
end
transition.to(object, params)
end
end
Thanks to all of you!
I accomplished the goal by doing so:
local segmentTransition
local delta = 1
local function onCompleteMove()
i = i + delta
if timeTable[i] then
segmentTransition = transition.to(player2, {
time=timeTable[i],
x=tableX[i+delta],
y=tableY[i+delta],
onComplete=onCompleteMove
})
end
end
onCompleteMove() -- start moving

price in menu+total price (pascal)

My program should allow the user to choose ice cream from menu then add the price for the ice cream to show total price of the ice cream.However my output for total price is wrong. For example if i choose 1 and 2 the answer should be 1.5+1.7=3.2 but I get 3.4. Also if i choose 2 I'll only get error. Please help me.
program iceCream;
var
count,i: integer;
price:array[1..50]of real;
totalPrice: real;
choice: integer;
begin
count:= 0;
writeln ( ' ICE CREAM FLAVOUR');
write ( ' 1.Vanilla: RM 1.50 | 3.Chocolate: RM 2.00');
writeln;
write ( ' 2. Strawberry: RM 1.70 | 0. Exit ');
writeln;
repeat
write ( ' Enter your choice(number): ');
readln ( choice);
if choice <= 3 then
count:= count+1
else
writeln ( 'Invalid choice');
case choice of
1: begin
price[i]:= 1.50;
end;
2: begin
price[i]:= 1.70 ;
end;
3: begin
price[i]:= 2.00;
end;
end;
for i:= 1 to count do
begin
totalPrice:= totalPrice+price[i];
end;
until choice = 0;
writeln ( ' Total ice-cream: ', count);
readln;
writeln ( ' Total price: RM ', totalPrice:2:2);
readln;
end.
I won't answer your question here. It's more important to find out what you're doing wrong and how you can solve the problem on your own.
How to find out what's going wrong?
The compiler shows two warnings when it compiles your code:
Warnings: 2
project1.lpr(29,17) Warning: Variable "i" does not seem to be initialized
project1.lpr(44,25) Warning: Variable "totalPrice" does not seem to be initialized
This kind of warnings appears when you read a variable without having a value assigned to it. The compiler leads you to the location of the unsafe code. The first warning is located in line 29 in column 17:
1: begin
price[i]:= 1.50; // i has not been set before. So its value is undefined or 0
end;
Is your intention to use set Price[i] here? So why hasn't it been assigned to a value before?
Or do you have a different variable that holds the number of ice creams? Why don't you use that?
Let's take a look at the second warning in line 44 in column 25. It's this line:
totalPrice:= totalPrice+price[i];
// ^
Are you sure totalPrice has been initialized correctly?
Even though you initialize it correctly the program may still doesn't work properly. In that case it helps to debug the application.
Open your application in the Lazarus IDE and press F8 to step through your program. You go from line to during the execution of your program. You will see what's wrong then.

Pascal fatal error ";" expected but else founded

uses crt;
var
i: integer;
stav: integer;
prsten: boolean;
begin
clrscr();
stav:=0;
prsten:=false;
repeat
case stav of
0: begin //Zacatek hry//
writeln('Toto je hra, jsi Princ a jsi v lese.');
writeln('Na krizovatce muzes jit doleva = 1, nebo doprava = 2');
readln(stav);
end;
1: begin
writeln('Potkas draka, ktery vezni krasnou princeznu. ');
writeln('3 = Prepadnout draka, 4 = Promluvit s nim');
readln(stav);
end;
2: begin
writeln('Potkas pocestneho. ');
writeln('5 = Pokracujes dal lesem, 6 = Promluvit s pocestnym');
readln(stav);
end;
3: begin
writeln('Drak je silnejsi nez Ty a tak te rozprasil na popel.');
writeln('Zacni znovu stisknutim klavesy 0.');
readln(stav);
end;
4: begin
writeln('Drak Te vyzve na souboj, ale Ty na nej nejsi jeste pripraven.');
writeln('Musis pokracovat dal lesem. Stiskni 5.');
readln(stav);
end;
5: begin
writeln('Po dlouhe a namahave ceste jsi dorazil do mistni knajpy.');
writeln('Najis a napijes se a pokracujes dal. Kousek od knajpy potkas pocestneho');
writeln('Promluvis s nim. Stiskni 6.');
readln(stav);
end;
6: begin
writeln('Povis mu, ze se pokousis zachranit princeznu pred drakem.');
writeln('On se ti rozhodne pomoci a daruje Ti kouzelny prsten.');
writeln('Nasadit prsten na ruku a pokracovat k drakovi 7 / Strcit prsten do kapsy 8 a pokracovat k drakovi.');
readln(stav);
end;
7: begin
writeln('Prijdes k drakovi a das se s nim do boje.');
writeln('Draka zabijes a muzes pokracovat k princezne.');
writeln('Pokracovat k princezne, stiskni 9.');
prsten:=true;
readln(stav);
end;
8: begin
writeln('Prijdes k drakovi a das se s nim do boje.');
writeln('Draka zabijes a muzes pokracovat k princezne.');
writeln('Pokracovat k princezne, stiskni 9.');
readln(stav);
prsten:=false;
end;
9: begin
if prsten then
writeln('Princeznu jsi uchvatil a muzes si ji odvest do hradu.');
else
wrtieln('Princezna je rada, ze jsi ji zachranil, ale opovrhuje Tebou.');
readln(stav);
end;
end;
until stav<0;
writeln('KONEC');
readln;
end.
What is causing the fatal error ";" expected but else founded message?
Unlike C, in Pascal a semicolon ; separates statements, it does not terminate them, and the then clause requires a single statement. then WriteLn(...); else is two statements; you want then WriteLn(...) else.
Let's take this opportunity to learn how to read and use error messages to your advantage.
The compiler tells you exactly what the error is (it's a ; before an else, because both of those are mentioned in the error message). It also gives you the exact line number where it's reporting the error; that's the number (usually in parentheses right before the error message, like (from Delphi):
[DCC Error] Project2.dpr(14): E2153 ';' not allowed before 'ELSE'
So the error is happening on line 14 (in my code - your number will be different). Let's look at that line and a few before and after:
if prsten then
writeln('Princeznu jsi uchvatil a muzes si ji odvest do hradu.');
else
wrtieln('Princezna je rada, ze jsi ji zachranil, ale opovrhuje Tebou.');
So look at the error message:
';' not allowed before 'ELSE'
That clearly tells you that the ; in the line before the else is the problem (that's very clear, because it says not allowed), so remove it.
BTW, now you're going to get another error:
[DCC Error] Project2.dpr(15): E2003 Undeclared identifier: 'wrtieln'
I think you should be able to figure that one out; again, the compiler gives you the exact line number.
You're going to get another one, if you've posted your entire code:
[DCC Error] Project2.dpr(18): E2029 Statement expected but end of file found
This is because you've left out the end. that marks the end of a program file in Pascal. If you've not posted your entire code, you may not get it.
It's important to learn to actually read the words when you get an error message from the compiler. In most languages, the messages are clearly worded, and they all have information you can use to try to figure out (or at least narrow down) the problems in your code.

TQuery Float field is implicitly rounded to integer when using ODBC

I'm querying 1 value from table. In db it's value is 48.8
When my app use BDE's native Oracle SQL Link driver, everything is Ok, it's still 48.8.
Then I make the app to use another BDE alias, which use ODBC data source (latest driver from Oracle). And now displayed value is 48.0
Details
The column is factW NUMBER(10, 3).
Test code:
var
q: TQuery;
begin
q := TQuery.Create( SELF );
try
q.DatabaseName := 'Realize';
q.SQL.Text := 'SELECT factW, TO_CHAR(factW) charW'
+'FROM bSertific WHERE id_sertific = :id';
q.ParamByName('id').AsInteger := dm1.Sertif1ID_SERTIFIC.AsInteger;
q.Open;
ShowMessage( ' factW = '
+ FloatToStrF(
q.FieldByName('factW').AsFloat,
ffFixed,
5, 3 ) // here 48.000
+ ' charW = ' + q.FieldByName('charW').AsString // here 48.8
);
finally
q.Free;
end;
end;
I hadn't find a proper solution. The workaround is to query the field as a string and convert it back and forth on the client side.

Resources