Panorama X 10.2 is a major release with a long list of changes. Here is a quick list of the major new features.
For more information about these major features, as well as many more minor new features, performance enhancements and bug fixes, consult the detailed list below.
Mixing 10.2 with Earlier Versions – We don’t recommend mixing Panorama X 10.2 with earlier versions of Panorama. If you have multiple computers, you should upgrade all of them to 10.2 at the same time, and remove any copies of Panorama X 10.1. Mixing versions can result in false “damaged database” alerts, see Database is Damaged Alert.
Panorama X 10.2 is a “Universal” app that is fully native on both Apple Silicon (M1, etc.) and Intel processors. For most tasks this new version is 3 to 6 times faster on Apple Silicon processors than previous versions of Panorama X.
The most important major new feature of version 10.2 is the inclusion of Panorama X Team Server, including database sharing and database web publishing. Database sharing allows multiple users to share one or more databases in cooperation. Each user access the data through their own copy of Panorama X on their computer. The server keeps everything organized so that multiple users can view and modify data without interfering with each other and keeping everything up-to-date. Users can share data across a local network or even across the internet.
Database web publishing allows information in a Panorama database to be viewed and modified using a web browser – Safari, Chrome, Firefox, etc. With database web publishing your databases can reach a global audience – anyone with a browser on any type of device and/or operating system.
To learn more, see Panorama Server.
Important Note: Access to the server features requires signing up for the Deploying Shared Databases video class. Please visit How do I sign up for the Deploying Shared Databases course? if you are interested in signing up for this course and using the server.
If you’ve used Panorama 6 Enterprise Server, you’ll find that many aspects of Panorama X Team Server are very familiar, but there are some significant differences:
Panorama X Team Server is much simpler to install and configure. You’ll never have to worry about configuring Bonjour Threshold again. Shared database configuration and administration tools are now integrated into Panorama, instead of being stuck into a submenu of the Wizard menu.
Panorama X Team Server runs completely in the background, with no windows, menus or dock icon. Launching, shutting down, and configuration of the server is performed using the Preference dialog of a standard copy of Panorama running on the same computer (this copy of Panorama only needs to be open when actually configurating the server).
By default, Panorama X Team Server is locked to your account for increased security. If necessary access can be granted to specific alternate accounts (for example if you need to give access to a consultant), or security can be disabled.
Improved server variables (see letservervariable, adjustservervariable).
A new preference setting in the Client preferences panel controls whether the user is prompted when a new generation of a database is available. The new default is to simply install the new generation without asking for confirmation.
The various “fill” statements (FormulaFill, Propagate, Unpropagate, PropagateUp, UnpropagateUp, RunningTotal, RunningDifference) now work much faster in most situations when used with shared databases, and only transfer to the server data cells that have actually changed. Also, the serverformulafill statement can now use variables in both the selection and fill formulas.
Panorama X Team Server does not support modification of shared databases when offline. You can always view any database, but you cannot edit a database unless you are connected to the server.
Most web code written for Panorama 6 Enterprise Server will run with little or no modification. The modifications needed are usually less than what is needed for regular Panorama code since web code usually doesn’t deal with operating system or user interface changes.
Web code can now use the save statement, the special websave statement is no longer required (though still allowed).
The Web Form Converter has been redesigned and now allows you to see a preview of how your form will look on the web without having to use an external web server. The logic of the converter is the same except for Image Display objects, which will require adjustment.
Panorama X Team Server can be run in conjunction with Terminal.app so that you can view console output from the server in real time, and Panorama X includes new tools for generating console output for debugging.
There is no CGI Simulator wizard, but it is now much easier to debug web code on a live server (partly because of the previous item).
Many database applications require multiple database files working together. In previous versions of Panorama this was primarily accomplished with lookup( functions. This could generally get the job done, but was tedious because there was no overall definition of the relationship between the databases. This approach required the application developer to manage all the tedious details of database relations manually – a lot of extra work to set up and very difficult to change if the database structure ever changed. This manual approach could also be prone to errors since all of the details had to be manually managed by the programmer.
Panorama X 10.2 introduces a completely new, systematic approach to relationships between databases. Each relationship is managed in one place, with a comprehensive, easy to use visual dialog panel. This relationship is permanent (saved with the database) and can be quickly applied wherever needed. Many common relational database tasks are now built in, and available automatically once a relation is set up. Other tasks can be accomplished with simple dialogs and/or with far less code than was previously required.
Note: For compatibility with existing database applications, legacy features like lookup( functions are of course still available and will continue to work, but these are now considered obsolete and are completely unecessary for new development.
To set up a relational link between the current database and one or more other databases, use the Database Options>Relations dialog sheet. This panel allows you to tell Panorama what the common fields are between two databases.
This panel may look complicated, but if the databases have exactly corresponding fields a relation can be set up in seconds with just a few clicks. See Relational Database Management to learn all the details about configuring a relation with this dialog. If the fields don’t exactly correspond, you can set up formulas to tell Panorama how they do match up.
Once a relation has been established between two databases, you can use that relation to quickly select data that corresponds to the current database, to display related information in a form, to accelerate data entry of related information, to post updated data to a related database, and to perform a full join between two databases.
If the current database has one or more databases related to it, additional items are added to the Search menu to allow you to quickly select data related to the current record. These extra items also appear in the menu that appears when you click on the record count in the tool bar. This illustration shows how easy it is to select data related to the current record.
Note: For clarity, the illustration shows the Vendor and PayTo fields as the active fields in the respective databases, but this is not necessary. Unless the relation involves a line item field, it doesn’t matter what field is active when the selection is made.
A relational selection can also be programmed into your own custom code, see selectrelated to learn how to do this.
Panorama has two functions that can be used to display related data on a form. When using these functions the related data is not copied into the current database, but it can be displayed as if it was part of the current database. This example uses the related( function to display the address of the company the check was written to, even though the address is stored in a separate database.
If the formula is constructed properly, the related data display will update automatically as you switch from record to record (see related( to learn how to ensure this happens).
If you expect there to be multiple records related to the current record, use the relatedarray( function. This example uses this function to display a list of all of the checks written to this vendor. Again, the list of checks is being displayed directly from the related Checkbook database, without ever being copied into the Vendors database.
This example uses a Text List Object to display the list of checks, but you can also use a Matrix Object or a Text Display Object.
Panorama’s relational system can be tightly integrated with Clairvoyance™ (auto-complete) and with data entry. To illustrate this, I’ll use two databases set up for a hobby shop – a sales database (order entry) and a customer account database. These databases are related as shown by the arrows in this diagram.
To see how remotely linked Clairvoyance™ works, just start typing into the Name field in the sales database (this diagram shows the form instead of the data sheet, but the underlying data is the same and relations work the same in either view.) The contact information in the order form is linked to the customer database, so Clairvoyance™ kicks in across databases to auto-complete the name.
When the return or tab key is pressed, Panorama uses the pre-defined relation to populate all of the contact information in the new order. Note that this auto join happens completely automatically – there is no coding needed, or even a formula (other than formulas set up in the relation definition).
This order form database is also relationally linked to a catalog (price list) database. When I start typing an item into the order, Clairvoyance™ auto-completes the entry for me from the catalog, even if this item has never been entered into an order before.
When the return or tab key is pressed, Panorama automatically populates the price and calculates all totals.
Simply rinse and repeat to complete the rest of the order.
To learn how to set up Auto Join and Remote Clairvoyance™ see Relational Database Management.
Note: Panorama X 10.2 also includes a new joinonerecord statement works like join, but only for the current record instead of for the entire current database. This new statement is used by the auto-join feature, but you can also use it in your own code in lieu of the lookup( function for data entry.
When two databases share common information, a simple one line program using the posttorelated statement can be used to update a related database with changes made in the current database, as shown in this diagram.
The same program will work to add completely new records to the related database.
There’s not much more too it, but see the posttorelated statement for additional details.
The final operation available for related databases is a full relational join. To perform a join, Panorama scans both the current and the related database, identifies all matching records, and updates the current database with information from the matching records in the related database. Optionally, it can also append any non-matching data from the related database into the current database.
This new join capability is much simpler and faster than the old method of using formulafill with a lookup( function – in our tests the join statement was able to join a single field between two 20,000 record databases in 3 seconds, vs. 7 minutes when using formulafill with a lookup(! The join feature can join multiple fields at once (no limit) for even larger performance gains over previous versions, and can is capable of the same types of inner and outer joins available in modern SQL systems.
To perform a join into the current database, choose File>Import>Join Panorama Database with Current Database. This opens the Join Database dialog.
This dialog allows you to select the database you want to join from, and to customize the options for the join. See Join Databases to learn more.
The join operation can also be programmed into your custom code. See the join statement to learn how to do this.
For even more detailed information about the new relational database capabilities, see these pages:
In addition to the new server and relational capabilities, many other improvements and fixes have been implemented in this new version. Panorama X 10.2 is probably the second biggest leap in Panorama’s 32 year history, only falling short of the jump from Panorama 6 to Panorama X 10.0.
The new posixtask statement and posixtask( function allows shell scripts to be run in the background. The shell output (stdout and stderror) can be directed to a variable, and can even be displayed dynamically as the script runs so that you can monitor the progress of long tasks. Essentially you can now construct a Panorama window that works much like Terminal.app. There is also a new stopposixtask statement and info(“posixtasks”) function.
When using the Data Sheet in Big Sur, Panorama now correctly updates the highlighted cell when moving left or right within a row.
Icons in the toolbar that were vertically misaligned in macOS 10.15 and later are now correctly lined up.
Fixed problem that could cause Clairvoyance to be unreliable with certain data combinations.
New menu command Hide Line Item Fields makes it easy to get line items out of the way when working in the data sheet. This command only appears in the Field menu if the database has line items. This command is recordable, and tere is also a new hidelineitemfields statement.
The Web Browser Object now supports Apple’s modern WKWebBrowser framework when running on a version of macOS that supports it. This enables faster web browsing, and protects Panorama itself from malformed web content (Panorama won’t crash even if the web browser does). This also enables enhanced customization and bridging between Panorama and JavaScript. See Web Browser Programming to learn more.
You can now use the Preferences dialog to choose the default action in the Find/Select Dialog – either Select (as before) or Find.
The GetText, GetTextOkCancel, and GetTextDialog statements now activate the text field automatically when the dialog opens (so you can just start typing without having to click in the dialog first).
The GetTextDialog statement has a new sheets option that causes the dialog to appear as a sheet attached to the current window, instead as a standalone modal dialog.
All windows now have a unique numeric ID. This allows code to reliably reference a particular window, even if that window has been renamed. For an overview of this new feature, see Window ID Numbers. The window statement and windowinfo( and windowglobalvalue( functions have been updated to allow windows to be specified by ID number. The new functions info(“windownumber”), info(“windownumbers”), info(“datasheetwindownumbers”), info(“formwindownumbers”), info(“procedurewindownumbers”) and listwindownumbers( functions return ID numbers. The getformoption( and getprocedureoption( functions have been updated to optional return window number ID’s. The new function info(“clickedwindownumber”) returns the number of the window the mouse was clicked in (which may be different from the active window). The new info(“dropwindownumber”) function is used to find out what window a drag and drop operation wound up on. Finally, the magicwindow statement now allows a window number to specify the window, as an alternate to the window name.
The Preferences->Favorites panel now allows you to specify one or more databases to be automatically opened when Panorama is launched. A database can also be opened secretly, or as a library. See Automatic Startup Database.
If a loop isn’t written correctly, it can continue running endlessly, causing Panorama to freeze. To prevent this problem, you can now set up a preference to specify the maximum time that a loop can run. Choose Preferences from the File menu, then click on the Advanced panel. In this panel you can edit the timeout value directly or you can choose from a set of common timeouts from the popup menu. Choose ∞ if you don’t want a timeout, but rather the option to run endlessly forever (this is the default). See Preventing Endless Loops to learn more about this feature, including how to set up custom timeouts for each different procedure (the timelimit statement and info(“timelimitremaining”) function).
The new containsword operator is similar to contains but only matches complete words (partial words do not match).
Added support for x-callback-url interapplication communication. This includes the xcallbackurl statement and the panoramax://
url scheme with x-callback-url support with two actions – panoramax://x-callback-url/run/database/procedure/label
and panoramax://x-callback-url/wizard/wizard+name
(or wizard%20name
). This enables interopability between Panorama and programs that use the x-callback-url protocol, including Ulysses, Drafts and Bear.
The new startfilesystemmonitorstatement can monitor file system changes, allowing you to run custom code whenever a watched file or folder changes.
The new Timer Workshop is a tool for monitoring timers and creating and testing timer configurations. A special thank you to Gary Yonaites for the idea of this workshop, and for writing most of the Create Timer panel in this workshop.
The Fill and Formula Fill dialogs now have an icon for inserting field names. When you click on this icon (upper left) a popup menu of field names appears. Choosing a name inserts it into the dialog, with chevrons if necessary.
The new openasyncprogresswindow statement makes it super easy to display a progress window for long running tasks like downloading large files from the internet. It’s designed to be paired with the urltask( function, but can also be used with timers.
The Customize Toolbar dialog sheet (that appears when you right click on the toolbar) now displays the labels of each tool, not just the icons.
New alwayskeepopen database option. If enabled, the database won’t close when all its windows are closed, but will stay open secretly in memory. This can be enabled in the Database Options>General panel, or with the setdatabaseinfo statement (and observed with the dbinfo( function).
Two new tools are available in the data sheet, Copy Record and Paste Record. (Note: These tools are not in the toolbar by default, you must right click on the toolbar to open the Customize Toolbar dialog sheet, then drag these tools into place.) Special thanks to Gary Yonaites for the icon design of these new tools.
If a database contains an .Initialize
procedure, that procedure now runs immediately when a database is opened. If a database is opened by code, the code following the opendatabase or openfile statement doesn’t run until after the .Initialize
procedure is finished (this is different than in versions 10.0 and 10.1, where the .Initialize
code wouldn’t run until after the code in the original procedure). You can now even put an alert or dialog in the .Initialize
procedure, though that is still not considered a best practice. If an .Initialize
procedure encounters a runtime error, a notification will appear, but any code following the opendatabase/openfile statement will still run normally. Finally, the .Initialize
procedure is now documented in the Custom Database Initialization help page.
New implicit form actions: formGRAPHICSMODE:
and formDATAMODE:
allow custom code to run when switching in and out of graphics mode. See Implicitly Triggered Procedures to learn how to use form actions.
New menu command Source>Copy Indented Code for procedure windows. This command copies the currently selected code (or the entire procedure if nothing selected) onto the clipboard, but with four leading spaces. The text can then be pasted into the ProVUE Forum for perfect code formatting. Voila!
Added new _OnErrorCode variable for trapping errors in a specific database or window. This makes it possible to eliminate any chance of the user seeing an error alert in that database or window. See Error Handling to learn more about this new feature.
If a code error occurs while a dialog is open, Panorama now displays an error alert as it did before, but when this alert is closed, the dialog closes as well. This eliminates the possibility of a dialog getting “stuck” open. In the past you could press the ESC key to close the dialog and continue with normal operation, but few users were aware of this option and most would resort to force quit. If the Enable Advanced Error Dialog option is enabled (in the Advanced panel of the Preferences dialog), the error alert will also offer the option to open the Error Wizard to display more information about the problem.
When importing a Panorama 6 database into Panorama X, the form preferences for tab order are now imported correctly for the Natural and Back-to-Front options.
A Popup Menu Button Object now has a choice of data sources, either Field/Variable (like before) or Formula. If the source is Formula, then any formula can be used, not just a field or variable. The choice is placed into a fileglobal variable named PopupMenuResult. This is similar to the Formula mode of a Text Editor Object. This makes it makes it much easier to use a popup editor to edit things that aren’t fields or variables, for example preferences.
The Open View dialog is now more “keyboard friendly” for fast, keyboard only operation, more like Xcode’s “Open Quickly” dialog. 1) When the dialog initially opens, the search text is automatically highlighted, so you can just type 2) As you type in a search, the first matching view is automatically highlighted, so you can just press Return to open it. 3) You can press Command-Down and Command-Up to move up/down thru the matching items using the keyboard, then press Return to open 4) Press Command-Delete to clear the search text, starting a new search with a single keystroke.
Text List and Matrix objects now update when data in the current record is updated (when the Database Navigator option is enabled).
The new measuretext( function returns the height and width (points) of a string of text in a specified font and size.
New hidefieldsbetween statement makes it easy to look at only the first and last few fields in a database.
New titlecase( function, which capitalizes first character of each word, but not articles, prepositions, and conjunctions under 5 characters (unless they are the first or last word in the text). This function was suggested by Stan Ulrich and implemented by Gary Yonaites – thank you! In addition to the function itself, a Title Case option has been added to the capitalization pop-up menus in the Morph Field Dialog and the Morph All Fields Dialog.
New blindposixscript( function allows Panorama code to run a UNIX script in the background.
New filebookmark( and bookmarkpath( functions allow the name and path of a file to be stored persistently, even if the file is moved or renamed.
New ability to save and measure images on the clipboard. Use the ClipboardImageSave statement to save the image on the clipboard and the ClipboardImageSize( function to measure it.
Panorama now includes a new Global Dictionaries feature for high performance dictionary applications. The new global dictionaries are much faster than the existing data dictionary feature (however, they are more inconvenient to use).
The new procedureexists( function provides a fast an easy way to check to make sure that a procedure exists, as you might want to do before attempting to call it.
New labelize( function saves double typing of field/variable names when displaying a field or variable in a log or message.
New editfield statement begins editing of the specified field, as if the user had clicked on that field.
New BooleanValue( function, which makes it easy for subroutines, custom statements, and custom functions to evaluate boolean parameters in a friendly way.
Adds six separate new functions for encoding URL components – encodeurlfragment(, encodeurlhost(, encodeurlpassword(, encodeurlpath, encodeurlquery( and encodeurluser(. Because of these new function, the urlencode( function is now considered obsolete. You should not use it in any new applications, and may want to review how it is being used in existing applications.
New ability for a subroutine to access and modify the local variables of its caller, using the callerslocalvariablevalue( and info(“callerslocalvariables”) functions, and the setcallerslocal statement. Use this new unstructured capability with care.
New straightquotes( function converts smart quotes into straight quotes.
New loremipsum( function generates dummy text. Thanks to Gary Yonaites for contributing this code.
New constant( function generates a formula constant from any expression.
New formulastrings( function extracts a data array of all text constants in a formula.
New ConvertVariablesToConstants statement does exactly what it says – takes a formula and replaces any variables with the actual value of the variables.
New openurlinbackground statement, works like openurl but doesn’t bring the app forward. For example you can open a web page without bringing the web browser forward.
When importing or exporting CSV text files, Panorama now uses semicolon (;
) as the default field separator if the system preferences are set to use a comma as the numeric decimal point (for example in much of Europe). See importtext, importline, databaseexportcsv, csvexportline(, csvexportlinevisiblecells(, csvtotsv( and info(“csvseparator”).
Added two new functions for converting TSV (tab separated) text fields into other formats. The tsvtocsv( function converts the text into comma separated text. The tsvtojson( converts the text into JSON.
Added new statement StdOut, which sends one or more characters to the terminal console. Unlike the NSLog, no additional time/date stamp is added, giving the programmer complete control over the text to be output.
Add four new statements and a new function for application management: BringPanoramaForward, HidePanorama, HideOtherApplications, PanoramaAppVisibility, and info(“panoramaisactive”).
Added the new OpenWithTerminal statement, which will open any application using Terminal.app. This makes it easy to see any console output from the program, which is very handy for debugging.
New fileattributes( function for accessing file attributes like the creation and modification date, permissions, etc. The corresponding modifyfileattributes statement allows these attributes to be modified via code.
Implemented the SavePartialDatabase and PartialDatabaseUpdate statements, which can be used as a pair to transfer procedures, forms, field properties, etc. from one database to another, without disturbing the data.
New zipcompress function, which works like compress but uses the ditto
shell tool to do the compression (which makes for much easier extraction of compressed folders). Thanks for the inspiration from Gary Yonaites.
New zipuncompress statement, properly unzip’s compressed files created by the Finder and by the zipcompress statement.
Added the progresssync option to the urltask( function. This enables display of progress of multiple asynchronous downloads simultaneously in a Matrix object (as an example, this is used in the Server Administration Wizard.
The openform statement has a new option, NoVersionButton, that allows you to remove the caret icon just the the right of the window title (at the top of the window), and removes the ability to click on the title to rename the document, or to Command-Click on the title to see the path to this document. This option is now used on all wizard and utility windows (About Panorama, Memory Usage, Formula Workshop, etc.).
Added new object action to matrix objects – getcelltext. This action gets the current text from a specific cell in the matrix (if the matrix is using a query, there is no other way to get this). The syntax is:
objectaction "object",“getcelltext”,cellnumber,variable
Added three new statements that can customize the banner that appears in the middle of data windows (this banner normally shows the number of selected/total records). The SetBannerProgressBar statement displays progress from 0 to 1 as a background bar in this banner (the URLTask( function has also a new option to display progress in this banner). The SetBannerMessage statement allows you to temporarily customize the message that appears in this banner. The SetBannerIcon statement allows you to add a small icon on the right hand side of the window, for example a lock icon.
If you write special code to customize the tab order, that code can now cancel the tab operation by returning empty text (""
) (see Custom Tab Order).
Fixed multiple problems with group objects, in particular, objects that edited variables now work if included in a group (Text Editor, Checkbox, etc.) and tooltips now work with objects included in a group.
The Find & Open dialog now excludes any Panorama Server databases on the computer (if the server is running on the same computer), and any databases in the /Application Support
folder
Added new serverlookup(, serverlookupall( and serversuperlookup( functions, added these functions to the Relational Workshop wizard, and removed the Use Server for Lookup option from the form preferences panel.
The copypartialdictionary( function now allows the second parameter to be a carriage return delimited list of key names, making it much easier to generate this list with a formula.
The database parameter of the formulavalue( function is now optional. If omitted, the current database is assumed.
Added new functions formulaidentifiers(, formulafields( and formulavariables(. This functions return a list of identifiers (fields and/or variables) referenced in a formula.
Added new dictionaryfromarray( function and setlocalsfromdictionary statement. These can be combined to easily transfer variables from one context to another.
Added new posixscript( function, which is similar to shellscript( but uses a native Cocoa API (NSTask) instead of AppleEvents to run the script (in some situations this is much faster).
New runningappinfo( function returns information about a specific app currently running on the computer, or all running apps. This function is very fast, much faster than using a shell script to perform the same task. The new Instruments panel uses this function to check to see if Console.app is running.
New usefunctioncallerslocalvariables statement allows code in a call( function to access the local variables of the code that called it.
New timerexists( function makes it easy to check whether a timer is currently running.
Timers can now be locked with a password (see starttimer). If the operation of a timer is critical, this can prevent casual users from inadvertently disrupting timer operation.
The dbinfo( function now has a lockmessage option, so that code can find out the status of the most recent attempt to lock a record. It also includes over a dozen new options for accessing the client/server options associated with a database.
The views( function has a new option, viewtypes, which restricts the output to specified types of views, either procedures, forms, or data sheet.
New croptext( function, cuts off text if it is too long, adding ellipsis to indicate that it is cut off.
New calledby( function allows a procedure to check whether it was called from a specific procedure, a specific database, or both.
Added PartialDatabaseSaveDialog and PartialDatabaseRevert statements, should be handy for debugging, allowing database to be modified and then reset back to a known state, even if the database is shared (for shared databases, this only works if the client and server are on the same computer).
New editcellwith statement works like editcell but pre-loads the editor window with any text you want. The database isn’t modified until editing is complete.
Changed dbinfo(, info( and getfieldproperties( functions to allow formulas to access to field names and field information even when the user cannot change the design of the database (now this information is only restricted if the user is not allowed to use standard UI). This allows the Find/Select, Sort, Morph Field, Summarize & Analyze and Hide/Show Fields dialogs to work properly when the user is not allowed to change database design.
The dumpdictionaryquoted( function now outputs any binary values in the dictionary as [[[BINARY DATA]]]
(instead of spewing out a bunch of random looking garbage).
New function dumpdictionarysource(, useful for building blueprints that contain a dictionary. Also the new dictionaryassignmentscode( function generates executable code from a dictionary, to convert a dictionary into separate fields or variables.
The setfieldproperties statement now allows the database and field name to be specified, so now any field in any open database can be modified, not just the current field in the current database. If these parameters are omitted, it works exactly as before, maintaining compatibility with existing code.
Added the DatabaseConsoleDump and ServerDatabaseConsoleDump statements. These statements were developed to assist ProVUE with debugging, but they are available for anyone (as long as you run Panorama under Terminal.app).
New Advanced tab added to the Preferences dialog.
The Client panel of the Panorama Preferences now allows you to choose Notification or Alert to appear when a server error occurs.
Fixed multiple significant bugs in the copyfile statement. 1. It now checks to make sure that the destination folder is writeable. 2. It now creates the destination folder if it doesn’t already exist (as Panorama 6 did). 3. It now replaces the destination file if it already exists (as Panorama 6 did).
Fixed multiple significant bugs in the copyfolder, copynewerfile and copynewerfolder statements, and added a new copynewerfile( function. The folder copying statements now have the ability to filter the list of files being copied, and to report the progress of the copy back to the calling program.
Multiple changes have been made to the protocol used by the ..PostSynchronize
procedure (if present, this procedure is called during client synchronization. If you have a database with this procedure, you may need to make adjustments (see synchronize). First of all, ..PostSynchronize
is now always called, even if no records were downloaded. The second change is that ..PostSynchronize
is now called with a dictionary instead of 4 separate parameters. The final change is that synchronization no longer displays a notification if there is a ..PostSynchronize
procedure, in that case, the ..PostSynchronize
procedure must display the notification itself (the default notification message is passed in the dictionary if you want to use it, or you can customize your own message).
Added new wait and ExecuteASAP statements to facilitate running code with a slight delay. The new info(“runningatomic”) function checks to see whether or not code is using the normal run loop. Code that runs outside of the run loop is now called Atomic Code instead of ..Handler code. There is now an extensive explanation of how Panorama code interacts with the run loop in Understanding the Run Loop.
The new waitfortask and resumeaftertask statements facilitates coordination between synchronous and asynchronous code. The new setwaitinglocal statement allows asynchronous code to pass data back to the synchronous code that spawned it. The urltask( function now converts any «taskid»
tags in the source code into the actual task id, for use with the resumaftertask and setwaitingglobal statements.
In the Panorama Help wizard, the Topic>Copy Topic URL command now actually copies the URL onto the clipboard, instead of just notifying you that it has done so.
Delete field no longer crashes if you delete the last field and the next to last field is hidden. Also now refuses to delete if there is only one visible field.
Printing variable height rich text no longer causes a crash. It prints as fixed height text, not variable height, but it doesn’t crash.
Try/catch now correctly restores local variables after an error. Also normal error handling is restored after an error occurs within a try/catch segment. Up until now, if an error occured in a try/catch segment, that segment remained active (sort of). So if an additional error occured later in the code, that error would not be handled correctly (it would just cause the code to stop, without an error).
If used in a try/catch block, the stop statement no longer stops - instead it throws an error that will be handled by the catch statement (see Error Handling). This change prevents things from getting mucked up if a stop statement is included in tasks like .Initialize
or in server code.
Fixed problems with menu bar updating under Big Sur (and possibly earlier).
Summary records are now given record ID’s in a unique range that immediately identifies them as unshareable, so that they are kept segregated from regular data records. All summary records are removed when uploading a database to the server (or a new generation). The info(“unsharedrecordid”) returns the minimim value in this range.
The Group Up and Group Down commands now stop with an error if there are no visible data records (before this fix, this action could cause loss of data). Also the Summarize & Analyze Dialog no longer allows you to add a Group Up step below the Outline step (though you can still drag the actions into the incorrect order).
When merging a field into a Text Display Object or Web Browser Object, for example «field»
, Panorama now uses the output pattern for that field, instead of just default str( conversion (if an output pattern has been set up).
The val( function now works with fractional values even when the system’s decimal point is set to a comma (for example 1,23). Also, the val( function now has an optional second parameter that allows you to explicitly specify the decimal point character.
When importing text into a floating point field, a standalone dash is now interpreted as zero. Apparently depending on the format chosen Excel sometimes exports empty numbers as dashes.
When printing Variable Height Records (expand or expand/shrink), Panorama now considers empty text to be zero height (actually not quite zero, still leaves space for vertical padding and descender).
Fixed floating point fields to allow values with more than one place in front of the decimal point. For example, 12.34 was rejected as invalid, while 1.234 was allowed. Now both are ok.
The new foldersize( function calculates the size of a folder (or a package). (It returns the same size as the Finder Get Info window.)
The new obfuscate( function randomizes the letters and digits in text (but leaves punctuation alone).
The new getstructurevalue( function makes it much easier to extract items from a nested structure of dictionaries & data arrays.
The urldecode( function now works when % is double encoded, for example a space is %2520. This was encountered in URL’s passed from the Ulysses x-callback-url feature.
Fixed the urldecode( function so that it correctly converts %25 to %.
The asc( function no longer crashes if given empty text, instead it returns zero.
The OpenFile statement can now be used with the if error
statement. Also, it no longer creates a new untitled database if it is passed a file that does not exist without an extension.
No longer displays weird error messages when user uses the escape key to get out of Open File dialog with no windows open.
The OkCancel, CancelOk, AlertOkCancel and AlertCancelOK statements now have an OK
button instead of Ok
. This matches Panorama 6 and also conforms to Apple user interface guidelines.
The lookup( function now allows a “bare” field or variable to be used as the default value (just as this was allowed in Panorama 6). This also works in the related functions lookuplast(, lookupselected(, lookuplastselected( and table(.
Fixed the pluralpattern( function so that it works even if a word contains “are” embedded inside it. For example, this formula now works correctly even though “shared” contains “are”: pluralpattern(1,“# shared database~ are open”)
The onewhitespace( function now correctly converts linefeeds to spaces, in addition to carriage returns, tabs, and multiple spaces.
The closeactiveobject statement now works in the data sheet, and with pop-up text editing in a form. (Before it only worked with regular Text Editor objects). Als, the CloseActiveObject statement has a new synonym – CloseEditor.
The Group Up and Group Down statements now update the record counter display, as they should have all along.
The SetPermanentVariable statement no longer fails if the value parameter is a single token (i.e. a single field or variable).
The formulamerge statement now handles formula errors properly.
The rangecontains( function now works correctly.
The info(“languagecode”) function now will return non-English languages.
The clipboard() function no longer crashes if the clipboard contains an image instead of text.
The info(“modifiers”) function now works with keyboard events (it used to only work with mouse clicks).
The new closeclonewindow statement is an alternate method to close the current window, it will work even if the window doesn’t have a close box.
New functions info(“panoramaversion”) and info(“panoramabundleversion”) do just what you would think they do.
New functions info(“processname”) and info(“processidentifier”) return information about the running copy of Panorama for use in UNIX scripts.
New function info(“panoramauptime”), returns number of seconds since Panorama was launched.
New function jsonscriptstring( facilitates the creation of JSON strings.
Panorama’s JSON export functions now use "
instead of '
as quote character. According to the spec either are ok, but Apple’s JSON parser doesn’t like the single quotes.
When displaying a date without using a pattern, Panorama now displays the full 4 digit year if the date is more than 95 years ago or more than 5 years in the future. This also fixes problems when editing a date outside that range, when copying a record that contains a date outside that range, and when importing a database that contain dates outside of that range.
When the system preferences are set to a region with a date format of mm/dd/yy (most of the world outside of the US), Panorama now allows entry and import of dates in the format dd-mon or dd-mon-yyyy.
Anywhere a date is entered (date fields, date( and datevalue( functions) now correctly checks for dates past the end of a month, including leap years (before it only checked for number of days past 31). For example, Panorama now knows that April 31 is not a valid date.
Data entry of days of the week (Sun, Mon, Tue etc.) now respects the system setting for the first day of the week. So if the system settings say the first day of the week is Monday, data entry of “Sunday” will refer to the upcoming Sunday, not the previous one.
Change default filename extension when exporting HTML from export wizard to .html (otherwise it will be .txt, as before).
The Print Preview commands now work properly if the database name has a slash (/) in the name.
Reports generated with the Construct Report feature (see Automatic Report Construction) now default to truncate tail instead of word wrap. This can be controlled in the constructor with the <linebreakmode>
tag.
The <grid:dashed>
(or <grid:dash>
) tag now works correctly when using the List/Matrix constructor (see Text List Constructor).
The FirstColumn and LastColumn statements now display a better error message if you try to use them in a form or procedure window.
The AbortAllDialogs statement now works correctly with dialog sheets (before it only worked with modal dialogs).
The record counter now updates correctly after a revert to save is performed.
Command-K (remove summaries) now works immediately after grouping or any operation that adds a summary record (total, count, etc.), without having to actually click on the menu bar.
Since the single step feature doesn’t work reliably, the single step tool has been removed from the default tool bar configuration.
The Credentials panel of the Site License window now makes it more difficult to mess up the account email address. Before, it would allow you to edit the email address to anything, even an empty email address. Now it requires you to enter a non-empty email address, and it asks for confirmation before submitting an email address change. (A customer tried to modify their passwords and inadvertently set the email address to empty.)
It’s now possible to delete the first query row in the Find/Select dialog.
In previous versions the Text Editor object was erroneously creating a fileglobal variable when in Formula mode, using the entire formula as the field name!
The openform statement has a new option, NoVersionButton, that allows you to remove the caret icon just the the right of the window title (at the top of the window), and removes the ability to click on the title to rename the document, or to Command-Click on the title to see the path to this document. This option is now used on all wizard and utility windows (About Panorama, Memory Usage, Formula Workshop, etc.).
In the Relational Workshop wizard, clicking on the green thumbs up icon in the Lookup Results panel no longer displays a blank alert (or any alert). If there is a red thumbs down icon, it still displays the error message.
The RemoveAllSummaries statement now checks to see if there actually are any summaries before it bothers to scan all the records. Just a possible slight (but easy) performance enhancement.
Starting a procedure with the Run button in the procedure window now sets the trigger to “RUN TOOL (procedure window)”.
Text List Objects now respond to the open action (see objectaction) by acquiring focus, so that they are responsive to keyboard activity (up/down, etc.).
New info(“eventtype”) function allows code to find out of the most recent event was a mouse click, key press, or something else.
Added documentation for the info(“loggedinaccountrole”) and info(“loggedinaccountemail”) functions.
Took out the star from the Find & Open dialog, it didn’t do anything except break Panorama when clicked.
Data Button objects now properly set up the clicked object id, clicked object name, and button rectangle when they are clicked.
Clicking the object opacity stepper button no longer appears to increase object opacity from 100% to 101%.
The Web Browser object now correctly adjusts when flipping between Literal and Formula mode. Before you also had to make a change to the formula after flipping the mode, or close and re-open the window.
The SuperAlert statement now works correctly when using a SuperAlertDefaultOptions variable, even if the text in that variable doesn’t contain a leading space.
The jsonimport( function no longer crashes if a null value is supplied in the JSON. Since Panorama has no way to represent null, it is converted to zero bytes of binary data.
The min and max statements and the aggregate( function now work with 64 bit values outside of the 32 bit range.
Added a new type of error, a null value. Unlike any other error value, a null value can be stored in a dictionary. A null value can be created with error(“null”) or error(“nil”) (or any error beginning with null/nil). The jsonimport(/jsonexport( functions will convert between JSON null values and the special null error value.
When displaying literal text, Panorama now adds a parenthesis around each embedded formula. This prevents interaction between the formula and the surrounding text. Consider {Price-Cost}
. In previous versions, this would produce an error because it was converted to {}+Price-Cost+{}
. {}+Price
results in a string, which then produces an error when you try to subtract Cost
. Now it is converted to {}+(Price-Cost)+{}
which works.
The unixshellstring( function no longer escapes a tilde character (~) if it is the first character of the text.
When an error occurs in building form objects using a constructor template, Panorama now shows you the error, and offers to re-open the template editor dialog so that you can correct the error.
When constructing a report, the objects would shift over 24 points every time the report was generated, but only IF no left margin was specified. If the left margin was > 0, it worked ok. Now it works either way.
The SuperChoiceDialog statement font and size tags now work as documented, and fixed display of the caption when using this statement.
The addlines statement now works correctly when a variable or text constant is supplied for the first parameter, instead of a database field.
Fixed the randomline( function, it was completely broken.
Conversion of floating point numbers to text (for example with the str( function) now defaults to 15 digit precision instead of 16 (since IEEE format does not conatain 16 full digits). In addition, there is a new setdefaultfloatformat statement that allows you to change the conversion format, and info(“defaultfloatformat”) that returns the current setting. However, these are considered “unsupported.”
The Morph Field dialog now displays the result preview using the output pattern for the field being morphed, so it’s much more usable for numeric and date fields.
Added findselect statement for compatibility with ancient Panorama 1.x code (it does the same thing as the findselectdialog statement, it does not recreate the “classic” find/select dialog).
The sample data for the checkbook tutorial now contains field names on the top row, so that the data matches the tutorial documentation.
New writepreference statement. Mostly for the purpose of implementing the new panoramax://writepreference?name=value
feature that allows arbitrary preference values to be changed with a link.
Panorama now checks for an error when checking the computer’s MACID for when setting up the account. (This change was made after a user encountered an error due to a bad ethernet port in his Mac Mini, so that he could not log on to Panorama X on that computer.) If there is an error, it now uses the MACID of the alphabetically first network interface. It is also possible to force a specific network interface. There is also a new function that returns the MACID of the network interface that is registered with Panorama, the panoramamacid( function. See the documentation of this function for details on customizing what network interface is used.
RemoveSummaries now checks to make sure there is at least one visible record after the summaries are removed, and if not, performs a select all. If there are no data records at all (they have been deleted) and the statement would delete all summary records, it stops with an error to make sure that the database cannot be left with zero records (which is disasterous).
Pressing the tab key no longer inserts tabs into multi-line areas in property panels. This was reported for Choices but actually was possible in about a dozen areas, all of which are now fixed.
The lineitemarray( function no longer strips out empty elements in the middle of the array (empty elements on the end are still stripped off).
If used in a try/catch block, the stop statement no longer stops - instead it throws an error that will be handled by the catch statement. This prevents things from getting mucked up if a stop statement is included in tasks like .Initialize
or in server code.
The Formula Workshop now displays dates in the appropriate format based on System Preferences settings.
The Site License window now allows you to create custom plans, making it possible to purchase more than 60 months at a time.
In the Site License->Computers panel, the Recent Activity column is now a few pixels wider, so that wide dates don’t get cut off.
Eliminated spurious console warning “.sdef warning for argument ‘FileType’ of command ‘save’ in suite ‘Standard Suite’: ‘saveable file format’ is not a valid type name.”
Panorama X no longer crashes if you attempt open a damaged Panorama 6 database with no data (zero bytes).
Several hundred documentation corrections submitted by Robert Ameeti, David Thompson, Michael Kellock, Gary Yonaites, Thomas Cooper, Kurt Meyer and Craig MacPherson.
Brand new features implemented in this release (features that were not included in Panorama 6):
Features implemented in this release that work differently than they did in Panorama 6.
Features implemented in this release that work exactly the same as they did in Panorama 6.
ALL features that were added or changed in this release:
See Also