LibreOffice Calc Macro: printing a sheet gives 'no such method or property: $(ARG1)" - printing

I have a spreadsheet containing data in lines on several sheets. These sheets are named arbitrarily (not sheet1 sheet2 nor any similar scheme).
I need to extract some info from one of the lines of the current sheet (I give the number of the line in an input box), then put this info on another sheet to format it, then print that formatted sheet, and finally go back to the initial sheet I was on (one of those containing data).
So far I have come up with this code: (I omit the line selection and data copying because that works)
' Sheets("facture").PrintOut
Dim oDoc as Object
oDoc=ThisComponent
Dim sPrefix$ ' Prefix used to identify the print listener routines.
Dim sService$ ' Print listener service name
sPrefix="print_listener_"
sService="com.sun.star.view.XPrintJobListener"
If NOT oDoc.sheets().hasByName("facture") Then
MsgBox "Le document n'a pas de page nommée 'facture'"
Else
Dim oSheets
oSheets = oDoc.Sheets
Dim currentSheet
currentSheet = oDoc.getcurrentcontroller.activesheet
oDoc.currentController.setActiveSheet(oSheets.getByName("facture"))
oPrintListener=CreateUnoListener(sPrefix,sService)
oDoc.addPrintJobListener(oPrintListener)
'oPrintJobListnerDoc=oDoc
oDoc.Print(Array())
wait 12000
oDoc.currentController.setActiveSheet(currentSheet)
However, when I run it, the data is correctly formated on my output sheet, but the VB window pops up with 'BASIC runtime error: property or meethod not found: $(ARG1)'.
If I remove the 'wait 12000' and 'oDoc.currentController.setActiveSheet(currentSheet)' then the data is printed correctly but Calc stays on the output sheet, and doesn't get back tot the initial sheet I was on (obviously).
If I only remove the 'wait 12000', nothing happens, and the data is not printed.
Can anybody help? Thanks!

The general principle of waiting for the end of printing can be expressed as follows
REM ***** BASIC *****
Public Statex1 As Integer ' Through this variable, the event handling procedure will notify the main program
Public oPrintJobListnerDoc As Variant
Sub PrintOutFacture()
Dim oDoc As Variant
oDoc=ThisComponent
Statex1=0
oPrintJobListnerDoc = CreateUnoListener("print_listener_", "com.sun.star.view.XPrintJobListener")
oDoc.addPrintJobListener(oPrintJobListnerDoc)
Rem ...Prepare the print - fill the cells with the desired values, format, define the print area, etc.
oDoc.Print(Array()) ' It might not be an empty array, but a whole bunch of print options!
While Statex1=0 ' 1 = Printing completed, 3 = Print canceled
Wait 100
Wend
oDoc.removePrintJobListener(oPrintJobListnerDoc)
Rem ...Post-Print Actions - Switch the sheet, close the document, or do something else
End Sub
Sub print_listener_printJobEvent(oEvent As Variant)
Statex1 = oEvent.State ' Pass the value of the State field of the oEvent to the main program through the Public variable Statex1
End Sub
Sub print_listener_disposing
End Sub

Related

DXL: Need to extract data from previous object baselines

Basically, I have to go through all baselines of an object until I get the author who modified "_ReqStatus" attribute and copy that value in "_Ownr" attribute. Everything is working fine for the current baseline, but I cannot get through the older baselines of the module. I have to mention that I run the script for 2000 objects each one having at least 20 baselines.
My code looks like this:
//scriptul recunoaste obiectele cu "ReqStatus modifica"
pragma runLim, 0
Module m = current
History h
HistoryType ht
Object o
string attributName
string attributNameBaseline
string authorName
string newOwner
Baseline lBaseLine
noError()
for o in entire m do {
**for lBaseLine in module(o) do{ //These 2 code lines were my try to load all baselines
Module lBaseMod = load(module(o), false) //but with no results**
for h in o do
{
string owner = ""
attributName=""
attributName = h.attrName
authorName=""
owner = o."_Owner"
if isDeleted(o) then continue
if(attributName=="_ReqStatus")
{
authorName=h.author
//print authorName
//print "\n"
if(null owner)
{
print identifier(o)
print "\n"
newOwner = authorName
print newOwner"\n"
o."_Ownr" = newOwner
//print newOwner
break
}
}
}
}
}
ErrMess = lastError()
Thanks
Tony Goodman provides a script "Smart History Viewer" at http://www.smartdxl.com/content/?p=418, Michael Sutherland has one at https://www.ibm.com/mysupport/s/forumsquestion?id=0D50z00006HIGSUCA5, also, if you do a search on https://www.ibm.com/mysupport/s/forumshome for e.g. "dxl history" you might find some more code examples which should help you with this topic.
Your problem is the variable o. It is set only in the loop for o in entire m, it always refers to the o in the current version of m, never to the corresponding Object in a baseline. When you open the Module lBaseMod, o is not automatically reassigned.
So, use a new variable of type Object, set it to the Object in the baseline corresponding to o and browse through this new Object's history, see the linked scripts for reference.
Also, you should rework the flow of your script. With your approach, you open all the Baselines of m for each Object. In your case this means 2000 * 20 load and close. It will be much faster (though not necessarily less memory consuming) to open all the baselines of m in an outer loop, probably using a Skip list to collect the necessary information.
Also note that when you test your script, "print" becomes very slow after some time. It will be faster if you remember all the values that you want to print e.g. in a Buffer and print it at the end of your script, or write the output to a file.

How to get dxl scripts to run faster

I have created a DXL script that goes through every row of a couple modules. I am printing out certain rows and its information. I am doing this by having a for loop that goes through the rows and if it hits a row that I am interested in, I save the elements in the columns of this row to different string variables and print those string variables. The script does not take too long to run if the module does not have a lot of rows I am interested in but if I want to run multiple modules at the same time or if a module has a lot of rows I am interested in, the script can take hours. I can show the code that I have if this is not enough to come up with solutions. Any help would be appreciated!
I have tried using a skip list to store the print statements in that and then tried going through the skip list to print each value but that did not make the script run any faster.
string sep=","
for o in m do
{
string ver1= o."column1"
if (checkIf(o) && (!(isDeleted(o))))
{
string ver2= o."column2"
string onum=number(o)
""
string otext = o."Object Text"
print ver1 sep ver2 sep onum
}
}
Initial optimization:
for o in m do
{
if (checkIf(o) && (!(isDeleted(o)))) {
//This doesn't appear to be used?
//string otext = o."Object Text"
print o."column1" "," o."column2" "," number(o) "\n"
}
}
Reasoning: DOORS has a system in place called the string table that holds declared strings in memory- and doesn't necessarily do the best at clearing it out when appropriate. By constantly declaring strings in your loop, you might be bumping into the memory limits of that system.
Problem with this is that the results all end up in that 'DXL editor' little window, and then have to be copy and pasted somewhere else to actually use it.
Secondary optimization:
// Turn off runlimit for timing
pragma runLim , 0
// Set file location - CHANGE FOR YOUR COMPUTER
string csv_location = "C:/Users/Username/Desktop/Info_Collection.csv"
// Open stream
Stream out = append csv_location
// Set headers
out << "Module,Column 1,Column 2,Object Number" "\n"
// Define your loop constraints
Module m = current
Object o
// Run your loop
for o in m do
{
if (checkIf(o) && (!(isDeleted(o)))) {
//This doesn't appear to be used?
//string otext = o."Object Text"
out << fullName(m)","o."column1" "," o."column2" "," number(o) "\n"
}
}
close out
This will let you run the same script in different modules, all outputting to the same CSV file, which you can then load into Excel or your data manipulation engine of choice.
This keeps the data collection happening outside of DOORS, so if something goes awry, you can track down where it occurred.
My third optimization would be to use a list of modules in, say, excel as an input and do this analysis, but that might be going too far.
If this doesn't help, then we can start examining other issues.
Note- I still would like to know what 'checkIf' is/does.
If your objective is to speed up the execution of the script, since most of the objects are of no interest to you, the most effective way I know of is to filter out most of the objects that are not interesting, e.g., a filter which is obj."Object Text" != "" would filter out Headings, if you are just interested in requirements, obj."Object Text" contains "[Ss]hall" etc. Save as a view for later use.
for o in m do { respects the display set, so if you don't touch most of the objects it will speed it up a lot!
Hope this helps.
Don

how to keep track of object and object history information in a loop

I'm writing a DXL script to extract history information from all objects and write some of the history parameters into other attributes (columns) in the DOORS module. I started out with the example script in the DXL Reference Manual (rev 9.6, near page 333), which just prints the information into the DXL editor window. I tried to add some code to write to the attribute _Reviewer -- see below. The code as written looks at the currently selected object rather than the one to which the current h history belongs to. What's the safest variable to pass into the function print so I can access the desired object and write to its _Reviewer attribute?
// history DXL Example
/* from doors manual
Example history DXL program.
Generate a report of the current Module's
history.
*/
// print a brief report of the history record
// hs is a variable of type HistorySession
// module is a variable of type Module
void print(History h) {
HistoryType ht = h.type
print h.author "\t" h.date "\t" ht "\t"
//next 3 lines are the code I added to the manual's example
Buffer authortmp = create;
authortmp = h.author "\t" h.date "\t" ht "\t"
(current Object)."_Reviewer" = authortmp;
// other code from original deleted
}
// Main program
History h
print "All history\n\n"
for h in current Module do print h
print "\nHistory for current Object\n\n"
for h in current Object do print h
print "\nNon object history\n\n"
for h in top current Module do print h
I imagine that you want to set the _Reviewer attribute not only for one object but rather for all objects of the module. So you will have a loop over all objects and for each object you will have a loop over each of its history entries.
So, the main loop would be like
Module m = current
string sHistoryAttributeName = "_Reviewer"
if (null m) then {infoBox "Open this script from a module";halt)
// […]add more code to check whether the attribute "_Reviewer" already exists in the current module and whether the module is open in edit mode
Object o
for o in entire m do {
if isDeleted(o) then continue // deleted objects are not of interest
// perhaps there are more objects that are not of interest. add relevant code here
if (!canModify o.sHistoryAttributeName) then {warn "cannot modify history entry for object " (identifier o) "\n"; continue}
Buffer bContentOfReview = create
History h
for h in o do {
bContentOfReview += getHistoryContent(h) "\n"
}
o.sHistoryAttributeName = sContentOfReview
delete bContentOfReview
}
save m
and your function getHistoryContent would be similar to your function void print (History h), only that you will return a string instead of printing the history entry. Something like
string getHistoryContent (History h) {
HistoryType ht = h.type
string sReturnValue = h.author "\t" h.date "\t" ht ""
return sReturnValue
}
One additional hint: you wrote "into other attributes (columns)". The above solution is for persistent attributes. Instead of this, you might want to show the information in a view as a DXL Layout column or or as a DXL attribute -- both possibilities have the advantage that the information is more or less always up to date, but with a persistent attribute the information will only be current after you run the script. Also note that this approach will only give you the changes since the last baseline. If you need more, the problem will be more complex. See the Rational DXL forum or google for more complex solutions of showing history entries
//Edit: removed typo in string concatenation, use Buffer insted

VB6 SCGrid Textbox

Within a VB6 form, I'm using an SCGrid object were the cells are editable by means of a textbox.
I suppose the grid control creates a TextBox object as soon as the user clicks a cell.
I need a reference to this TextBox.
In particular, when the user presses the [Left] or [Right] key, I need the current position of the cursor within the textbox. I can then simply call TextBox.SelStart.
Does anybody know how to get the control used when editing a cell?
I figured it out myself:
' Declaration needed for getting the current position of the cursor
Private Type Point
x As Long
y As Long
End Type
Private Declare Function GetCaretPos Lib "user32" (ByRef lpPoint As Point) As Long
' This function returns the position of the cursor within the cell currently being edited as a TextBox
' The value is expressed as the number of characters preceeding the position
Private Function GetCaretPosition() As Integer
' Variables
Dim position As Point
Dim result As Long
Dim contents As String
' Get position
result = GetCaretPos(position)
' Convert it into number of characters
' I figured out the factor 15 by trial and error
' Don't know where it comes from but it seems independent of the font size
contents = myGrid.Text(row_gvar, column_gvar)
result = 0
While ((result < Len(contents)) And _
(position.x > (grid_gvar.Parent.TextWidth(Left(contents, result)) / 15)))
result = result + 1
Wend
' Done
GetCaretPosition = result
End Function

Elder Scroll Online Addon

This is my first time working with Lua, but not with programming. I have experience in Java, Action Script, and HTML. I am trying to create an addon for Elder Scroll Online. I managed to find the ESO API at the following link:
http://wiki.esoui.com/API#Player_Escorting
I am trying to make a function that returns a count of how many items each guild member has deposited in the bank. The code I have so far is as follows
function members()
for i=0, GetNumGuildEvents(3, GUILD_EVENT_BANKITEM_ADDED)
do
GetGuildEventInfo(3, GUILD_EVENT_BANKITEM_ADDED, i)
end
I am having trouble referencing the character making the specific deposit. Once I am able to do that I foresee making a linked list storing character names and an integer/double counter for the number of items deposited. If anyone has an idea of how to reference the character for a given deposit it would be much appreciated.
I don't have the game to test and the API documentation is sparse, so what follows are educated guesses/tips/hints (I know Lua well and programmed WoW for years).
Lua supports multiple assignment and functions can return multiple values:
function foo()
return 1, "two", print
end
local a, b, c = foo()
c(a,b) -- output: 1, "two"
GetGuildEventInfo says it returns the following:
eventType, secsSinceEvent, param1, param2, param3, param4, param5
Given that this function applies to multiple guild event types, I would expect param1 through param5 are specific to the particular event you're querying. Just print them out and see what you get. If you have a print function available that works something like Lua's standard print function (i.e. accepts multiple arguments and prints them all), you can simple write:
print(GetGuildEventInfo(3,GUILD_EVENT_BANKITEM_ADDED,i))
To print all its return values.
If you don't have a print, you should write one. I see the function LogChatText which looks suspiciously like something that would write text to your chat window. If so, you can write a Lua-esque print function like this:
function print(...)
LogChatText(table.concat({...}, ' '))
end
If you find from your experimentation that, say, param1 is the name of the player making the deposit, you can write:
local eventType, secsSinceEvent, playerName = GetGuildEventInfo(3,GUILD_EVENT_BANKITEM_ADDED, i)
I foresee making a linked list storing character names and an integer/double counter for the number of items deposited.
You wouldn't want to do that with a linked list (not in Lua, Java nor ActionScript). Lua is practically built on hashtables (aka 'tables'), which in Lua are very powerful and generalized, capable of using any type as either key or value.
local playerEvents = {} -- this creates a table
playerEvents["The Dude"] = 0 -- this associates the string "The Dude" with the value 0
print(playerEvents["The Dude"]) -- retrieve the value associated with the string "The Dude"
playerEvents["The Dude"] = playerEvents["The Dude"] + 1 -- this adds 1 to whatever was previous associated with The Dude
If you index a table with a key which hasn't been written to, you'll get back nil. You can use this to determine if you've created an entry for a player yet.
We're going to pretend that param1 contains the player name. Fix this when you find out where it's actually located:
local itemsAdded = {}
function members()
for i=0, GetNumGuildEvents(3, GUILD_EVENT_BANKITEM_ADDED ) do
local eventType, secsSinceEvent, playerName = GetGuildEventInfo(3, GUILD_EVENT_BANKITEM_ADDED, i)
itemsAdded[playerName] = (itemsAdded[playerName] or 0) + 1
end
end
itemsAdded now contains the number of items added by each player. To print them out:
for name, count in pairs(itemsAdded) do
print(string.format("Player %s has added %d items to the bank.", name, count))
end

Resources