Suche // Search:

22.12.2010

FormCalc Diagramme Teil 4-V2 - Liniendiagramm
//
FormCalc Chart Pt.4-V2 - Line Charts

Liniendiagramme sind alles andere als einfach in Designer herzustellen, aber dass es geht habe ich ja schon vor einiger Zeit gezeigt.
Die Version hatte allerdings einige Einschränkungen.
So mussten alle möglicherweise genutzten Liniem schon während der Design-Phase eingefügt werden, da es nur mit einem positionierten Layout möglich ist, Element übereinander zu legen.
Mittels eines Tricks ist das nun nicht mehr nötig.
Dafür genügen schon 4 Zeilen Code.
Kurz gesagt, sagen wir dem Formular erst, dass das Teilformular "Chart" fließend ist, was uns ermöglich von den eingeschlossenen Teilformulare "Line" und "Label" neue Instanzen anzulegen.
Dannach wird das Teilformular einfach wieder auf positioniert gesetzt, fertig.

Chart[j].layout = "tb"
Chart[j]._Line.setInstances(nRows)
Chart[j]._Label.setInstances(nRows)
Chart[j].layout = "position"

Des Weiteren ist das Diagramm auch nicht mehr auf einen kleine Darstellungsbereich beschränkt.
Mittels eines Faktors kann es Werte zwischen 0 und 10.000 dynamisch darstellen.


Line Charts aren't easy to realize in Designer, but a while ago I showed that it is still possible.
Well that version hat some restrictions.
One was, that all possibly used lines already had to added in the design phase, because only a positioned layout allows to lay element on top of each other.
With a small trick this isn't neccessary anymore.
Four lines of code are enough to do this.
In short, we tell the form that the subform "Chart" is flowing, which allows us to add more instances of the wrapped subforms "Line" und "Label".
After that, we reset the subform to positioned, done!

Chart[j].layout = "tb"
Chart[j]._Line.setInstances(nRows)
Chart[j]._Label.setInstances(nRows)
Chart[j].layout = "position"

Aditionally it is now possible to use the chart in a large value range.
With the use of a factor ist can display values between 0 and 10.000 dynamically.



Alte Hierarchie des Formulars - Jedes eventuell benötigte Objekt muss bereits vorhanden sein
//
Old hierarchy of the form - Every possibly needed object has to be already present

Neue Hierarchie des Formulars - Jedes Objekt ist erstmal nur einmalig vorhanden
//
New hierarchy of the form - Every object initially occurs only once


Neues FormCalc-Skript
//
New FormCalc script

var Check = RenderChart.value
if (Check eq "true") then
var Factor
var MaxInput = Max(Input.Table.ChartValues[*].Col[*].Amount)
var Fmin
var Fmax
for f = 0 upto 9950 step 50 do
Fmin = f
Fmax = Fmin + 50
if (Within(MaxInput, Fmin, Fmax) eq 1) then
Factor = 1 / (Fmax / 100)
endif
endfor

var nRows = Input.Table.ChartValues.instanceManager.count
var nColumns = Input.Table.ChartValues[nRows -1].Col.instanceManager.count
_Chart.setInstances(nColumns + 1)

var GraphValue
var GraphLabel
var PrevGraphValue
var GraphDiff
var LineStart
var ContainerHeight
var Offset

for r=0 upto nRows -1 step 1 do
for c=0 upto nColumns -1 step 1 do
Chart[c].layout = "tb"
Chart[c]._Line.setInstances(nRows)
Chart[c]._Label.setInstances(nRows)
Chart[c].layout = "position"
ContainerHeight = UnitValue(Chart[c].hLines.h, "in")
Chart[c].Line[r].y = ContainerHeight
GraphValue = Input.Table.ChartValues[r].Col[c].Amount
Chart[c].Line[r].presence = "visible"
Chart[c].Label[r].presence = "visible"
Chart[0].Line[r].presence = "invisible"

if(c eq 0) then
PrevGraphValue = 0
LineStart = ContainerHeight
else
PrevGraphValue = Input.Table.ChartValues[r].Col[c-1].Amount
LineStart = UnitValue(Chart[c-1].Line.LineGraph.y, "mm")
endif

for y = 10 downto 0 step 1 do
Output.yAxis.Mark[y].Mark.value.text.value = Round((10 - y) * 10 / Factor)
endfor

var nColor = Choose(r+1, ;Instance (+1) = position in this list
"238,0,0", ;Red
"255,99,71", ;Tomato
"255,127,80", ;Coral
"255,140,0", ;DarkOrange
"255,165,0", ;Orange
"255,215,0", ;Gold
"255,255,0", ;Yellow
"238,238,0", ;Yellow2
"154,205,50", ;YellowGreen
"69,139,0", ;Chartreuse
"0,139,0", ;Green
"0,139,69", ;SpringGreen
"69,139,116", ;Aquamarine
"82,139,139", ;DarkSlateGray
"0,139,139", ;Cyan
"0,134,139") ;Turquoise
Chart[c].Line[r].LineGraph.value.line.edge.color.value = nColor
Input.Table.ChartValues[r].Color.Color.value.rectangle.fill.color.value = nColor

GraphDiff = GraphValue - PrevGraphValue
Chart[c].Line[r].LineGraph.h = UnitValue(Abs(GraphDiff), "in") / 25.4 * Factor
Chart[c].Label[r].LineValue.value.text.value = GraphValue
GraphLabel = Input.Table.ChartValues[r].Label
Chart[c].Label[r].LineValue.assist.toolTip.value = GraphLabel

if(GraphDiff >= 0) then
Chart[c].Line[r].LineGraph.value.#line.slope = "/"
else
Chart[c].Line[r].LineGraph.value.#line.slope = "\"
endif

if(c eq 0) then
Offset = ContainerHeight - UnitValue(Abs(GraphDiff), "in") / 25.4 * Factor
Chart[c].Line[r].y = Offset
Chart[c].Label[r].y = Offset
else
if(GraphDiff >= 0) then
Offset = ContainerHeight - GraphValue / 25.4 * Factor
Chart[c].Line[r].y = Offset
Chart[c].Label[r].y = Offset
else
Offset = ContainerHeight - (GraphValue + Abs(GraphDiff)) / 25.4 * Factor
Chart[c].Line[r].y = Offset
Chart[c].Label[r].y = ContainerHeight - (GraphValue / 25.4) * Factor
endif
endif
endfor
endfor
endif
RenderChart.value = "false"




Liniendiagramm - mit automatischer Größenanpassung
//
Line chart - with auto-resizing


Beispiel // Example
https://files.acrobat.com/a/preview/a3e6c8e5-5311-4219-a6f7-d7a2f2259d50

20.12.2010

FormCalc Diagramme Teil 5 - Automatisch vergrößerndes, gestapeltes Säulendiagramm
//
FormCalc Charts Pt.5 - Auto-resizing, stacked Bar Charts

Dies ist eine Weiterentwicklung von dem gestapelten Säulendiagramm, dass ich vor einiger Zeit geposted habe.
Bei dem alten Beispiel störte mich die Beschränkung auf einen bestimmten Wertebereich.
War dieser nicht ausreichend groß dimensioniert, wuchs das Diagramm mitunter oben aus dem Darstellungsbereich heraus.

Mit einer kleinen Ergänzung im Berechnungsalgoritmus ist dies nun aber kein Problem mehr.

Mittels eines Faktors kann der Wertbereich beliebig groß definiert werden.
Dafür prüft eine For-Schreife, ob das größte aller Gesamtergebnisse innerhalb eines bestimmten Bereichs liegt.
Trifft dies zu, wird dann ein Faktor anhand dieses Wertes berechnet, der später in die Berechnung der Balken einbezogen wird.

Des Weiteren wird eine Formularvariable "RenderChart" verwendet, die verhindert, dass der Trigger das Diagramm auch neu berechnet, wenn gar keine Änderung an den Eingabedaten vorliegt.
Mit einem If-Ausdruck wird das ganze Berechnungsskript umfasst und nur dann ausgeführt, wenn die Formvariable den Wert "true" hat.


This is an upgrade of the stacked bar chart I've posted a while ago.
In this old example I get bothered by the limitation of the range of values.
If it was to small the chart began to grow out of the displaying area.

But, with a small addition to the algorithm I was able to solve this problem.

With the use of a factor the range of values can be as large as you like.
Therefor a for-loop is used, which checks if the largest of all total results is within a specific range.
If so, the factor will be calculated by this value and later reused to calculate the bars.

In addition a form variable "RenderChart" is used to suppress a recalculation of the charts if there has been no changes to the input values.
With an if-expression which surrounds the whole calculation script, the script is only executed if the form variable has the value "true".

FormCalc-Skript
//
FormCalc script:

var Check = RenderChart.value
if (Check eq "true") then
var Factor
var MaxInput = Max(Input.Table.ChartValues[*].Sum)
var Fmin
var Fmax
for f = 0 upto 9950 step 50 do
Fmin = f
Fmax = Fmin + 50
if (Within(MaxInput, Fmin, Fmax) eq 1) then
Factor = 1 / (Fmax / 100)
endif
endfor

var nRows = Input.Table.ChartValues.instanceManager.count
_Chart.setInstances(nRows)
var nColumns = Input.Table.ChartValues[nRows -1].Col.instanceManager.count
Chart[*].Stack._Bar[*].setInstances(nColumns)
Chart[*].Labels._Label[*].setInstances(nColumns)

for i=0 upto nRows -1 step 1 do
for j=0 upto nColumns -1 step 1 do
var BarValue = Input.Table.ChartValues[i].Col[j].Amount
for y = 10 downto 0 step 1 do
Output.yAxis.Mark[y].Mark.value.text.value = Round((10 - y) * 10 / Factor)
endfor

var nColor = Choose( j + 1, ;Instance (+1) = position in this list
"238,0,0", ;Red
;"255,48,48", ;FireBrick
"255,99,71", ;Tomato
"255,127,80", ;Coral
"255,140,0", ;DarkOrange
"255,165,0", ;Orange
"255,215,0", ;Gold
"255,255,0", ;Yellow
;"238,238,0", ;Yellow2
"154,205,50") ;YellowGreen
Chart[i].Stack.Bar[j].BarGraph.value.rectangle.fill.color.value = nColor
Chart[i].Stack.Bar[j].BarGraph.value.rectangle.edge.color.value = nColor

if (BarValue > 0) then
Chart[i].Stack.Bar[j].presence = "visible"
else
Chart[i].Stack.Bar[j].presence = "invisible"
endif

var ChartMod = UnitValue(BarValue, "in") / 25.4
Chart[i].Stack.Bar[j].BarGraph.h = UnitValue(ChartMod, "in") * Factor
Chart[i].Labels.Label[j].BarValue.h = UnitValue(ChartMod, "in") * Factor
Chart[i].Labels.BarTotal = Input.Table.ChartValues[i].Sum
Chart[i].Labels.BarLabel = Input.Table.ChartValues[i].Label

if(BarValue * Factor >= 3) then
Chart[i].Labels.Label[j].BarValue.value.text.value = Input.Table.ChartValues[i].Col[j].Amount
else
Chart[i].Labels.Label[j].BarValue.value.text.value = ""
endif

var ContainerHeight = UnitValue(Chart.h, "in")
var MoveHeight = UnitValue(Input.Table.ChartValues[i].Sum, "in") / 25.4 * Factor
Chart[i].Stack.y = ContainerHeight - MoveHeight
Chart[i].Labels.y = ContainerHeight - MoveHeight - UnitValue("5mm", "in")
endfor
endfor
endif


Beispiele gestapelter Balkendiagramme
//
Stacked Bar Charts Examples

Wertebereich 0 - 150 // Range of values 0 - 150


Wertebereich 0 - 550 // Range of values 0 - 550



Wertebereich 0 - 1300 // Range of values 0 - 1300




Bespiel-Formular
//
Sample form:
https://files.acrobat.com/a/preview/d9eaad0a-fea0-4303-8fd4-74a24fadb6fc


29.11.2010

Ausnahmeregelungen für Gesicherten Modus von Adobe Reader X erstellen
//
Create custom policies for Protected Mode of Adobe Reader X

So, Adobe hat's vollbracht und die neue Version 10 (alias X) von Acrobat und Reader veröffentlicht.
Einher gehen etliche Verbesserungen, vorallem die Sicherheit betreffend.

Der kostenlose Adobe Reader, der immerhin schon über 650 Millionen Mal geladen wurde, wurde ganz besonders verbessert.
Der sogenannte "Geschütze Modus" lässt den Prozess des Readers in einer Sandbox laufen, sodass PDF-Dateien ohne Weiteres keinen Zugriff mehr auf das Dateisystem bekommen, und somit auch bösartige Inhalte wie eingebetteter Shell-Code keinen Schaden mehr anrichten können.
Ich kann nur jedem empfehlen den Reader immer im Geschützen Modus zu verwenden!

Aber das Ganze hat auch Nebenwirkungen, die sich auf Workflows auswirken können, die auf Folder-Level-Skripte basieren, denn auch diese werden wirkungsvoll durch die Sandbox geblockt.

Ich hatte in einem früheren Beispiel mal beschrieben, wie sich XFA-Formulare mit einem Folder-Level-Skript in bestimmte Verzeichnisse speichern lassen.
Dies ist so ein Workflow, der nicht mehr funktioniert, wenn der "Geschützte Modus" aktiv ist.

Wenn Sie das Formular im Reader X mit aktiviertem Geschützem Modus testen, werden Sie nur einen Ausnahmefehler in der Konsole sehen.

NotAllowedError: Sicherheitseinstellungen verhindern den Zugriff auf diese Eigenschaft oder Methode.

Um diesen Workflow wieder gängig zu bekommen ohne auf die Sicherheit des Geschützen Modus zu verzichten, gibt es die Möglichkeit Ausnahmeregelungen in einer Whitelist für den Geschützen Modus zu definieren.

Die Einrichtung dieser Whitelist erfolgt in 2 Schritten.
Zuerst müssen Sie in der Registry einen neuen DWORD-Wert anlegen, damit Reader X überhaupt die Erlaubnis hat, die Whitelist zu verwenden.
Danach definieren Sie die Ausnahmeregelungen in der Whitelist selbst.

Well, Adobe has done it and released the generation 10 (alias X) of Acrobat and Reader. This generations brings a lot of enhancements.

Especially the free Adobe Reader, that already has been downloaded over 650 million times, was improved.
The so called "Protected Mode" runs the Reader process in a sandbox, so PDF files do not get access to the file system.
As a result malicious contents as embedded shell codes cannot harm the system.
I only can advise to use Reader always with the Protected Mode activated.

But, the also will have side effects to workflows that are working with folder level scripts, cause those script will also be blocked by the sandbox mechnism.

I an earlier example I had described, how to use folder level scripts to save XFA-forms into specific directories.
This is such a workflow that won't work with the "Protected Mode" activated.

If you use this example in Reader X with the Protected Mode activated, you will only see an exception in the console.

NotAllowedError: Security settings prevent access to this property or method.

To make it work again without deactivating the security of the Protected Mode, you can describe policies for the Protected Mode in a white list.

The setup of the white list has two steps.
You first have to create a new DWORD value in the registry to allow Reader X the usage of a whitelist.
Then you define the policies in the white list.

Ausnahmefehler in Reader X // Exception in Reader X



Schritt für Schritt // Step  by Step

Öffnen Sie den Registrierungs-Editor und suchen Sie den Verzeichniseintrag:
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Adobe\Acrobat Reader\10.0\FeatureLockDown

Erstellen Sie hier einen neuen DWORD-Wert namens bUseWhitelistConfigFile und weisen Sie diesem den Wert 1 zu.

Open the registry editor and look for the entry:
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Adobe\Acrobat Reader\10.0\FeatureLockDown

Create a new DWORD-value named bUseWhitelistConfigFile with the value 1.



Öffnen Sie den Programmorder von Adobe Reader X z.B. unter C:\Programme (x86)\Adobe\Reader 10.0\Reader\.
In dem Ordner muss sich die AcroRdr32.exe befinden, andernfalls funktioniert die Whitelist nicht!
Erstellen Sie hier eine Textdatei namens ProtectedModeWhitelistConfig.txt.


Open the program folder of Adobe Reader X under C:\Program Files (x86)\Adobe\Reader 10.0\Reader\ for example.
The folder has to contain the AcroRdr32.exe otherwise the white list won't work!
Create a new text file and name it ProtectedModeWhitelistConfig.txt.


Whitelist im Programmordner // White list in the program folder



Öffnen Sie die Textdatei, um die Ausnahmeregelungen zu definieren.
Insgesamt gibt es 8 Regelarten, von denen für diesen Workflow nur eine interessant ist. 
Die anderen sind vor allem für Entwickler von Plug-Ins interessant, weshalb ich darauf nicht weiter eingehe.


Es können beliebig viele Regelungen eingetragen werden, aber immer nur eine pro Zeile.
Kommentare werden in eigene Zeile geschrieben und mit einem Semikolon am Zeilenanfang auskommentiert.
Sie können Platzhalter für die Regelungen verwenden.
* für beliebig viele Zeichen  – jeweils nur eins in Reihe erlaubt
? für ein bestimmtes Zeichen – mehrere in Reihe erlaubt
Desweiteren können Sie Umgebungsvariablen wie z.B. %user%, %temp% oder %systemroot% verwenden, um die relativen Pfade zu den Systemordner aufzulösen.

Beispielregelungen:

; Laufwerk c:\ freigeben
FILES_ALLOW_ANY = c:\*

; Ordner mit dem Namen "LCB" freigeben – unabhängig davon wo der Ordner gespeichert ist
FILES_ALLOW_ANY = *\LCB\*

; Ordner des angemeldeten Benutzers freigeben – wie z.B. C:\Benutzer\Benutzername\
FILES_ALLOW_ANY = %homedrive%%homepath%\*

; PDF-Dateien beginnend mit "LCB_SaveAs" erlauben – wie z.B. LCB_SaveAs_Beispiel.pdf
FILES_ALLOW_ANY = *\LCB_SaveAs*.pdf

; PDF-Dateien generell erlauben (Nicht empfohlen!)
FILES_ALLOW_ANY = *.pdf


Open the text file to define the policies.
There are 8 rule types available, but only one is interesting for this workflow.
The others are more interesting for developers of plug-ins, so I won't use them here.

You can define as many rule as you like, but only one per line.
Comments have to be written in separate lines and are commented out be a semi-colon at the beginning of the line.
You can use wildcards for your policies.
* for several characters – only one in series allowed
? for one charecter – several in series allowed
Also, you can use enviroment variables such as %user%%temp% oder %systemroot%, to resolve the relative path to the system folders.

Example policies:

; Unblock drive c:\
FILES_ALLOW_ANY = c:\*

; Unblock the folder named "LCB" – no matter where the folder is stored 
FILES_ALLOW_ANY = *\LCB\*

; Unblock folder of current logged in user – like c:\user\username
FILES_ALLOW_ANY = %homedrive%%homepath%\*

; Unblock PDF files beginning with "LCB_SaveAs" – such as LCB_SaveAs_Example.pdf
FILES_ALLOW_ANY = *\LCB_SaveAs*.pdf

; Unblock all PDF files (not recommended!)
FILES_ALLOW_ANY = *.pdf


Eine Ausnahmeregelung in der Whitelist
//
A policy in the white list



Registrierungsdatei – zum Aktivieren der Whitelist für Adobe Reader X
//
Registry file – for activation of white list usage in Adobe Reader X
https://acrobat.com/#d=ssEHVn-3XANi7bbF9eZEVQ

Beispiel – Whitelist
//
Sample – white list
https://acrobat.com/#d=Z1HrB*ocHqklQX*w1bfiXg

04.08.2010

Sichere Passwörter erstellen
//
Generate secure passwords

Passwörter sind wichtig für die Datensicherheit, doch den Menschen fällt es schwer sich sichere Passwörter auszudenken und vor allem zu merken.
Es nützt wenig wenn man ein 12-stelliges Password verwendet, dass in jedem Duden steht.
Aus diesem Grund können noch immer viele Benutzerkonten mit einfachen Bruteforce-Attacken geknackt werden.

Dieses Formular soll Ihnen ein wenig unter die Arme greifen.
Es erstellt aus beliebigen Eingaben kryptische Passwörter mit Groß- und Kleinschreibung, Ziffern, Buchstaben und Sonderzeichen und mit bis zu 64 Zeichen.
Das generierte Passwort können Sie dann einfach per Strg + C kopieren und in das jeweilige Anmeldefenster einfügen.
Sie brauchen sich eigentlich nur das merken, was sie in Klartext eingeben.

Die Passwörter werden mithilfe eines SHA512-Algorhytmus erstellt, der in einem Scriptobject steckt.
Ein verstecktes Formularobjekt "Trigger" stößt dann die Berechnungen an.


Passwords are very important for data security but for people it's often difficult to think out secure passwords and especially to remember them.
A twelwe-digit password is possibly useless if it is a word you can find in every spelling dictionary.
That's why many accounts are still easy to capture through simple brute-force attacks.

This form should help you a bit with this scenario.
From any input it generates cryptic passwords with upper and lower case characters, digits and special characters, and a length upto 64 digits.
You can copy (ctrl + c) the generated password and paste it directly into your login window.
Actualy all you need to remember is the cleartext.

The passwords are generated by a SHA512 algorithm that is put into a script object.
All calculations are triggered by a hidden form object "Trigger".

Passwort-Generator // Password Generator:


Skript für Trigger // Script for Trigger:

var Cleartext = Input.value.text.value;
var PW_Length = Password_Length.value.text.value;
var PW_Coding = Password_Coding.value.text.value;
var PW_String 
if(Cleartext.length >= 1)
{
if(PW_Coding == "BASE64")
{
PW_String = SHA512.b64_sha512(Cleartext);
}
if(PW_Coding == "HEX")
{
PW_String = SHA512.hex_sha512(Cleartext);
}
if(PW_Coding == "ANY")
{
PW_String = SHA512.any_sha512(Cleartext, Cleartext);
}
Output.rawValue = PW_String.substr(0, PW_Length);
xfa.host.setFocus("Output");
}
else
{
Output.rawValue = null;
}


Beispiel // Example:
https://workspaces.acrobat.com/app.html#d=dvPh1TeA9NC3VUK3zBp15g

12.07.2010

Eigenen Installer für Formulare und Folder Level Skripte erstellen
//
Create own installer for forms and folder level scripts


Sicherheit ist wichtig, bringt aber auch Probleme mit sich. Wenn Sie mit Formularen und Skripten arbeiten, merken Sie schnell, dass sie bei Acrobat oder Reader die interessantesten Funktionen meist nur aus vertrauenswürdigen Umgebungen heraus ausführen dürfen.
Dafür müssen Sie die Skripte zum Teil in sogenannte Folder Level Scripts auslagern, die dann auf dem jeweiligen PC erst mal installiert werden müssen.
Das klappt in eigenem Büro meist noch ohne großen Aufwand.
Aber was, wenn sie ihre Dateien an Kunden verteilen, die von sowas keine Ahnung haben oder denen das zu aufwendig ist.

Ganz klar, bauen sie einen Setup, der das alles erledigt.
Dafür empfiehlt sich zum Beispiel die Freeware Inno Setup.
Durch diverse Zusatzprogramme ist es ein mächtiges Tool, mit dem sie sehr umfangreiche Installer mit professionellen Touch erstellen können.

Diese Methode bietet einigen Vorteile.
So können Sie beliebig viele Dateien unterschiedlichsten Typs mit nur einer Setup-Datei verteilen, die Benutzer brauchen lediglich den Setup einmal ausführen, um alles an seinem Platz zu haben und über die Deinstallationsroutine können sie auch alles auf einmal wieder entfernen.

Dieses Beispiel zeigt ihnen einen Installer, der prüft, ob ein Adobe Reader oder Acrobat installiert ist, dann den Pfad zu deren JavaScript-Ordner erstellt und ein Folder Level Script sowie einige XFA-Formulare installiert.
Der Installer ist zudem zweisprachig ausgelegt (deutsch und englisch) und mit eigenem Layout versehen.
Und das alles braucht weniger als 150 Zeilen Code.


Security is neccessary but causes other problems. Ic you work with forms and scripts you will learn that Acrobat or Reader allow the usage of interessting functions such as "saveAs" only from trusted enviromments.
Therefore you have to writhe part of your scripts into so called folder level scripts which have to be installed on each induvidual computer first.
In a office this maybe not the problem.
But what if your distribute your forms to customers who don't know how to install those files or don't want?

You will have to build a setup that will do this automatically.
Therefore the freeware Inno Setup is advisable.
With a lot of extensions available it's a powerful tool to create comprehensive installers with a professional touch.

This method offers several advantages.
You can distribute any number of files with different file types at once with only one setup-file.
Also, the users only need to execute the setup once to have everything in the right place and with the uninstall routine they also can remove all at once.

This example shows an installer that checks if there is an Adobe Reader or Acrobat installed.
If so it generates the path to the JavaScrips folder and installs a Folder Level Script and some XFA forms.
Also, the installer is multiligual (german and english) and has its own layout.
All done with less that 150 lines of code.

LCB Sample Installer:

1: Sprache auswählen // Select language










2: Installer prüft ob Acrobat/Reader installiert ist // Installer checks if Acrobat/Reader is installed







3: Installationsassistent startet // Install wizard runs















4: Aufgaben des Setups auswählen // Select task for the setup















5: Installation wird durchgeführt // Installation proceeds















6: Setup abschließen // Complete setup















7: Installierte Dateien im Programme-Menü // Installed files in the program menu


















8: Installiertes Folder Level Script // Installed folder level script















Inno Setup Code:
; LCB Installer Script
  #define MyAppName "LCB"
  #define MyAppVerName "1.0"


[Setup]
  AppId={{536B756A-54AA-4C37-8ADA-0C942B8327E7}
  AppName={#MyAppName}
  AppVerName={#MyAppName} {#MyAppVerName}
  VersionInfoVersion={#MyAppVerName}
  AppPublisher=Your Name Here
  AppComments=
  AppPublisherURL=
  AppSupportURL=
  AppUpdatesURL=
  AppCopyright=
  DefaultDirName={pf}\{#MyAppName}
  DisableDirPage=yes
  DefaultGroupName={#MyAppName}
  DisableProgramGroupPage=yes
  InfoAfterFile=SourceFiles\LCB_ReadMe.rtf
  OutputDir=FinalFiles
  OutputBaseFilename={#MyAppName}_Sample_Installer_{#MyAppVerName}
  Compression=lzma
  SolidCompression=yes
  SetupIconFile=SourceFiles\LCB_Icon.ico
  UninstallDisplayIcon=SourceFiles\LCB_Uninstall_Icon.ico
  UninstallDisplayName={#MyAppName} {#MyAppVerName}
  WizardImageFile=SourceFiles\LCB_Wizard_164x314.bmp
  WizardSmallImageFile=SourceFiles\LCB_Wizard_55x55.bmp


[Languages]
  Name: en; MessagesFile: compiler:Default.isl
  Name: de; MessagesFile: compiler:Languages\German.isl


[Files]
  Source: SourceFiles\ISSkin.dll; DestDir: {app}; Flags: dontcopy
  Source: SourceFiles\Styles\Office2007.cjstyles; DestDir: {tmp}; Flags: dontcopy
  Source: SourceFiles\LCB_SaveAs.js; DestDir: {code:ReturnPath}; Flags: ignoreversion
  Source: SourceFiles\LCB\*; DestDir: {app}\LCB\; Flags: ignoreversion recursesubdirs createallsubdirs
  Source: SourceFiles\LCB_ReadMe.rtf; DestDir: {app}; Flags: ignoreversion
  Source: SourceFiles\LCB_Licence.rtf; DestDir: {app}; Flags: ignoreversion
  Source: SourceFiles\LCB_Icon.ico; DestDir: {app}; Flags: ignoreversion
  Source: SourceFiles\LCB_Uninstall_Icon.ico; DestDir: {app}; Flags: ignoreversion


[Icons]
  Name: {group}\LCB SaveAs Sample; Filename: {app}\LCB\LCB_SaveAs.pdf; WorkingDir: {app}; IconFilename: {app}\LCB_Icon.ico
  Name: {group}\LCB Control View Sample; Filename: {app}\LCB\LCB_Control_View.pdf; WorkingDir: {app}; IconFilename: {app}\LCB_Icon.ico
  Name: {group}\LCB Stacked Bar Chart Sample; Filename: {app}\LCB\LCB_FormCalc_Charts_StackedBarChart.pdf; WorkingDir: {app}; IconFilename: {app}\LCB_Icon.ico
  Name: {group}\Uninstall LCB; Filename: {uninstallexe}; IconFilename: {app}\LCB_Icon.ico
  Name: {userdesktop}\LCB; Filename: {app}\LCB\LCB_SaveAs.pdf; WorkingDir: {app}; Tasks: desktopicon1; IconFilename: {app}\LCB_Icon.ico; Comment: Open LCB_SaveAs Sample
  Name: {userdesktop}\LCB; Filename: {app}\LCB\LCB_Control_View.pdf; WorkingDir: {app}; Tasks: desktopicon2; IconFilename: {app}\LCB_Icon.ico; Comment: Open Control View Sample
  Name: {userdesktop}\LCB; Filename: {app}\LCB\LCB_FormCalc_Charts_StackedBarChart.pdf; WorkingDir: {app}; Tasks: desktopicon3; IconFilename: {app}\LCB_Icon.ico; Comment: Open Stacked Bar Chart Sample


[Tasks]
  Name: desktopicon1; Description: Create shortcut on Desktop for SaveAs Sample; Flags: unchecked
  Name: desktopicon2; Description: Create shortcut on Desktop for Control View Sample; Flags: unchecked
  Name: desktopicon3; Description: Create shortcut on Desktop for Stacked Bar Chart Sample; Flags: unchecked


[Run]
  Filename: {app}\LCB\LCB_SaveAs.pdf; Verb: open; Description: Open LCB SaveAs Sample; Flags: postinstall shellexec unchecked
  Filename: {app}\LCB\LCB_Control_View.pdf; Verb: open; Description: Open LCB Control View Sample; Flags: postinstall shellexec unchecked
  Filename: {app}\LCB\LCB_FormCalc_Charts_StackedBarChart.pdf; Verb: open; Description: Open LCB Stacked Bar Chart Sample; Flags: postinstall shellexec unchecked


[CustomMessages]
  de.msgbox_1 =Setup hat einen geeigneten PDF-Viewer (Adobe Reader/Acrobat) auf Ihren Computer gefunden und kann nun fortgesetzt werden.%n
  de.msgbox_2 =%nGefundener PDF-Viewer: %n
  en.msgbox_1 =Setup found PDF-Viewer (Adobe Reader/Acrobat) on your computer and can be continued now.%n
  en.msgbox_2 =%nFound PDF-Viewer: %n
  de.msgbox_Error_1 =Fehler aufgetreten:%nEs wurde kein Adobe Reader bzw. Adobe Acrobat auf Ihrem Computer gefunden.%n%n
  de.msgbox_Error_2 =Sie müssen mindestens einen Adobe Reader 8.1 oder Adobe Acrobat 8 installiert haben,%num diesen Installer benutzen zu können.%n%n
  de.msgbox_Error_3 =Setup wird nun beendet.
  en.msgbox_Error_1 =An error occured:%nNo Adobe Reader or Adobe Acrobat could be found on your computer.%n%n
  en.msgbox_Error_2 =Install at least Adobe Reader 8.1 or Adobe Acrobat 8 first,%nbefore you use this Installer.%n%n
  en.msgbox_Error_3 =Setup will be aborted now.


[Code]
  procedure LoadSkin(lpszPath: String; lpszIniFileName: String);
  external 'LoadSkin@files:isskin.dll stdcall';
  procedure UnloadSkin();
  external 'UnloadSkin@files:isskin.dll stdcall';
  function ShowWindow(hWnd: Integer; uType: Integer): Integer;
  external 'ShowWindow@user32.dll stdcall';
  function InitializeSetup(): Boolean;
  begin
   ExtractTemporaryFile('Office2007.cjstyles');
   LoadSkin(ExpandConstant('{tmp}\Office2007.cjstyles'), 'NormalSilver.ini');
   Result := True;
  end;


  procedure DeinitializeSetup();
  begin
   ShowWindow(StrToInt(ExpandConstant('{wizardhwnd}')), 0);
   UnloadSkin();
  end;


  function CheckAdobeViewer(): String;
    var
    AdobeReaderVersion,AdobeAcrobatVersion,Version :  String;
    begin
    Result:='no';


  if  (RegQueryStringValue( HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe', '', AdobeReaderVersion))
    then
      begin
        GetVersionNumbersString( AdobeReaderVersion , Version);
        Result := 'Adobe Reader Version: ' + Version;
      end
  else
    if (RegQueryStringValue( HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Acrobat.exe', '', AdobeAcrobatVersion))
      then
        begin
          GetVersionNumbersString( AdobeAcrobatVersion ,Version);
          Result := 'Adobe Acrobat Version: ' + Version;
        end
  else
    begin
      MsgBox(ExpandConstant('{cm:msgbox_Error_1}') + ExpandConstant('{cm:msgbox_Error_2}') + ExpandConstant('{cm:msgbox_Error_3}'),MBError,mb_ok);
        begin
          Abort;
        end
    end
  end;


  function CheckAdobePath(): String;
    var
    FilePath: String;
    begin
      FilePath := '';
      if (RegQueryStringValue( HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe','', FilePath))
        then
          begin
            result := ExtractFileDir(FilePath) + '\JavaScripts\';
          end


  if (RegQueryStringValue( HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Acrobat.exe','', FilePath))
    then
      begin
        result := ExtractFileDir(FilePath) + '\JavaScripts\';
      end
  end;


  function  ReturnPath (Get:String):String;
    begin
      result := CheckAdobePath;
    end;


  procedure InitializeWizard();
  begin MsgBox(ExpandConstant('{cm:msgbox_1}') + ExpandConstant('{cm:msgbox_2}') + CheckAdobeViewer,MBinformation,mb_ok);
  end;



Dieses Script und auch einen fertigen Setup können Sie hier herunterladen.
Die Dateiendung des Setups müssen sie nach dem Download in *.EXE ändern!
Läuft unter Windows XP / Vista / 7 - 32Bit & 64Bit.

You can download this script and a working setup here.
After downloading the setup you need to change the file extension to *.EXE!
Runs under Windows XP / Vista / 7 - 32Bit & 64Bit.


Bespiel Inno Setup *.iss-Datei // Example Inno Setup *.iss file:

Beispiel Setup.exe // Example Setup.exe




Inno Setup und viele Erweierungen bekommen Sie unter folgenden URLs:


You can get Inno Setup and a lot of extenstion under the following URLs:


Inno Setup Download:
http://www.jrsoftware.org/isinfo.php

Inno Setup Erweiterungen // Inno Setup Extensions (3rd Party):
http://www.jrsoftware.org/is3rdparty.php

11.05.2010

FormCalc Diagramme Teil 4 - Liniendiagramm
//
FormCalc Charts Pt.4 - Line Chart

Ein Liniendiagramm ist ja der Klassiker schlechthin unter den Diagrammen.
Aber, um dieses Diagramm mit dem LiveCycle Designer herzustellen, ist etwas Aufwand nötig, da sich die Instanzen (sprich Graphen) ja überlagern können müssen.
Mit der Möglichkeit Teilformulare dynamisch hinzuzufügen und zu löschen kommt man hier also nicht weit, da sich die Instanzen in XFA-Formularen nur von links nach rechts oder oben nach unten anordnen.

Also muss hier alles, was evtl. angezeigt werden wird, schon im Formularlayout vorhanden sein.
Den Rest kann dann wieder ein einzelnes FormCalc-Script übernehmen.


The line chart is a real classic.
But, to realize it with LiveCycle Designer you need to expend effort.
That's because all instances (graphs) should be able to overlap each other.
Working with repeating subforms in XFA-forms won't work here, because these are only arraged next to each other from top to buttom or left to right and not on top of each other.

So, everything that could be shown later in the chart has to be in the form layout from the beginning.
The rest than could be done by a single FormCalc script.

FormCalc Script (sorry, sript looks a bit unpretty, because this blog editor has it's own life!):


var nRows = Input.Table.ChartValues.instanceManager.count 
var nColumns = Input.Table.ChartValues[nRows -1].Col.instanceManager.count 
_Chart.setInstances(nColumns)
var GraphValue
var GraphLabel
var PrevGraphValue
var GraphDiff
var GraphMod
var LineStart
var ContainerHeight = UnitValue(Chart.h, "in")
var Offset 

for i=0 upto nRows -1 step 1 do
for j=0 upto nColumns -1 step 1 do
if(j == 0) then
GraphValue = Input.Table.ChartValues[i].Col[j].Amount
PrevGraphValue = 0
LineStart = UnitValue(Chart[j].h, "in")
else
GraphValue = Input.Table.ChartValues[i].Col[j].Amount
PrevGraphValue = Input.Table.ChartValues[i].Col[j-1].Amount
LineStart = UnitValue(Chart[j-1].Line.LineGraph.y, "mm")
endif
Chart[j].Line[i].presence = "visible"
Chart[j].Label[i].presence = "visible"

;Select a color for the lines
var nColor = Choose(i+1,
"238,0,0",
"255,99,71",
"255,127,80",
"255,140,0",
"255,165,0",
"255,215,0",
"255,255,0",
"238,238,0",
"154,205,50",
"69,139,0",
"0,139,0",
"0,139,69",
"69,139,116",
"82,139,139",
"0,139,139",
"0,134,139")

Chart[j].Line[i].LineGraph.value.line.edge.color.value = nColor
Input.Table.ChartValues[i].Color.Color.value.rectangle.fill.color.value = nColor

GraphDiff = GraphValue - PrevGraphValue
Chart[j].Line[i].LineGraph.h = UnitValue(Abs(GraphDiff), "in") / 25.4
Chart[j].Label[i].LineValue.value.text.value = GraphValue
GraphLabel = Input.Table.ChartValues[i].Label
Chart[j].Label[i].LineValue.assist.toolTip.value = GraphLabel

if(GraphDiff >= 0) then
Chart[j].Line[i].LineGraph.value.#line.slope = "/"
else
Chart[j].Line[i].LineGraph.value.#line.slope = "\"
endif

if(j == 0) then
Offset = ContainerHeight - UnitValue(Abs(GraphDiff), "in") / 25.4
Chart[j].Line[i].y =  Offset
Chart[j].Label[i].y = Offset 
else
if(GraphDiff >= 0) then
Offset = ContainerHeight - GraphValue / 25.4
Chart[j].Line[i].y = Offset
Chart[j].Label[i].y = Offset
else
Offset = ContainerHeight - (GraphValue + Abs(GraphDiff)) / 25.4 
Chart[j].Line[i].y = Offset 
Chart[j].Label[i].y = ContainerHeight - (GraphValue / 25.4) 
endif
endif
endfor
endfor


Liniendiagramm // Line Chart:


Bespiel // Example:
https://files.acrobat.com/a/preview/34a5dfb2-392b-41e3-959d-11536d9a9b22