WordPress.org

Plugin Directory

Changeset 209432


Ignore:
Timestamp:
02/23/10 14:57:36 (4 years ago)
Author:
abelcheung
Message:

Sync from official repo

Location:
scorerender/trunk
Files:
19 added
13 edited

Legend:

Unmodified
Added
Removed
  • scorerender/trunk/ChangeLog

    r114490 r209432  
     12010-02-23  Abel Cheung  <abelcheung@gmail.com> 
     2 
     3    * wp-scorerender.php: 
     4    - (scorerender_conversion_hook) notation was not deactivated even when 
     5      corresponding notation program was unset. 
     6       
     72010-02-23  Abel Cheung  <abelcheung@gmail.com> 
     8 
     9    * scorerender-admin.php: 
     10    - (cache_location_match) Removed, not used anymore. 
     11 
     122010-02-23  Abel Cheung  <abelcheung@gmail.com> 
     13 
     14    * wp-scorerender.php, scorerender-admin.php: 
     15    - Drop CACHE_URL setting completely, now cached images are not accessed 
     16      directly via URL. 
     17       
     182010-02-23  Abel Cheung  <abelcheung@gmail.com> 
     19 
     20    * wp-scorerender.php, scorerender-admin.php: 
     21    - Now CACHE_DIR and CACHE_URL settings can be empty. 
     22    - Unanimously use scorerender_get_cache_location() to get cache image 
     23      folder. 
     24       
     252010-02-23  Abel Cheung  <abelcheung@gmail.com> 
     26 
     27    * wp-scorerender.php: 
     28    - (scorerender_get_cache_location) Can return both indexed or 
     29      associative array. 
     30       
     312010-02-22  Abel Cheung  <abelcheung@gmail.com> 
     32 
     33    * wp-scorerender.php: 
     34    - (scorerender_get_cache_location) New func, for getting location of 
     35      cache folder. Similar to the removed scorerender_get_upload_dir(). 
     36       
     372010-02-22  Abel Cheung  <abelcheung@gmail.com> 
     38 
     39    * wp-scorerender.php: 
     40    - (scorerender_add_ie6_style) Further removal of ancient WP support. 
     41 
     422010-02-22  Abel Cheung  <abelcheung@gmail.com> 
     43 
     44    * misc/tint-image.php: 
     45    - Accept user supplied color from GET variable. 
     46 
     472010-02-21  Abel Cheung  <abelcheung@gmail.com> 
     48 
     49    * notation/pmw.php: 
     50    - PostScript transparency for recent ImageMagick is properly detected. 
     51    - Add option to prevent reading config file. 
     52 
     532010-02-21  Abel Cheung  <abelcheung@gmail.com> 
     54 
     55    * notation/mup.php: 
     56    - Seems PostScript transparency is properly detected by ImageMagick 
     57      on recent Linux too. 
     58 
     592010-02-20  Abel Cheung  <abelcheung@gmail.com> 
     60 
     61    * wp-scorerender.php: 
     62    - (scorerender_get_options) Set default value of note color to 
     63      white if 'inverted image' option was turned on. 
     64 
     652010-02-20  Abel Cheung  <abelcheung@gmail.com> 
     66 
     67    * scorerender-admin.php: 
     68    - Move 'show source' setting to contents section. 
     69 
     702010-02-20  Abel Cheung  <abelcheung@gmail.com> 
     71 
     72    * scorerender-admin.php: 
     73    - (admin_footer, admin_section_content) Properly set disabled css 
     74      class for disabled input fields. 
     75 
     762010-02-20  Abel Cheung  <abelcheung@gmail.com> 
     77 
     78    * scorerender-admin.php: 
     79    - Encapsulate all functions inside ScoreRenderAdmin class. 
     80 
     812010-02-18  Abel Cheung  <abelcheung@gmail.com> 
     82 
     83    * wp-scorerender.php: 
     84    - (scorerender_process_content) Drop useless Exception handling 
     85      which can be replaced by normal logic. 
     86    * scorerender-class.php: 
     87    - (get_notation_name) Stop throwing useless Excepsion. 
     88 
     892010-02-18  Abel Cheung  <abelcheung@gmail.com> 
     90 
     91    * misc/tint-image.php: 
     92    - New file, to tint score images using color specified by user. 
     93    * wp-scorerender.php: 
     94    - (scorerender_process_content) Always output image using 
     95      tint-image.php. 
     96 
     972010-02-18  Abel Cheung  <abelcheung@gmail.com> 
     98 
     99    * wp-scorerender.php: 
     100    - (scorerender_get_upload_dir) Removed, now that WP 2.6 is required 
     101      and wp_upload_dir() is pretty much standardized since then. 
     102 
     1032010-02-17  Abel Cheung  <abelcheung@gmail.com> 
     104 
     105    * scorerender-admin.php: 
     106    - Move icon to images/ folder. 
     107    * wp-scorerender.php, scorerender-admin.php: 
     108    - Use plugins_url() where applicable. 
     109 
     1102010-02-17  Abel Cheung  <abelcheung@gmail.com> 
     111 
     112    * wp-scorerender.php, scorerender-class.php: 
     113    - Rename DEBUG constant to avoid potential name clash. 
     114 
     1152010-02-17  Abel Cheung  <abelcheung@gmail.com> 
     116 
     117    * MUP magic file setting is replaced by directly entering registration 
     118      key. 
     119    * wp-scorerender.php: 
     120    - Increase database schema version. 
     121    * notation/mup.php: 
     122    - (set_magic_file) Removed. 
     123    - (set_magic_file_hook) Renamed to more generic set_notation_action(). 
     124 
     1252010-02-17  Abel Cheung  <abelcheung@gmail.com> 
     126 
     127    * scorerender-utils.php: 
     128    - Remove wp_parse_str() backport, as WP 2.2 is no more supported. 
     129 
     1302010-02-17  Abel Cheung  <abelcheung@gmail.com> 
     131 
     132    * Completely drop 'inverted' setting, introduce 'note_color' setting. 
     133      Admin related changes are complete. In the future colored score 
     134      fragments are generated on the fly instead of storing multiple copies 
     135      of image with different colors. This requires proper support of alpha 
     136      channel in PHP GD extension, which is completely broken in some 
     137      platforms, such as Debian / Ubuntu except very recent releases. 
     138    * Now requires WP 2.6 due to usage of plugin_url(). 
     139    * wp-scorerender.php: 
     140    - Increase database schema version. 
     141    * scorerender-admin.php: 
     142    - (scorerender_admin_head) Add color picker CSS. 
     143    - (scorerender_admin_footer) New func, move existing JavaScript calls 
     144      here, and add Color Picker JavaScript calls. 
     145    - New WP hook to call scorerender_admin_footer(). 
     146    * scorerender-class.php: 
     147    - (ScoreRender::render) Only use input data sans whitespace as raw data 
     148      for hash calculation, so that whitespace change won't modify hash 
     149      value. 
     150 
     1512010-02-17  Abel Cheung  <abelcheung@gmail.com> 
     152 
     153    * images/*, misc/colorpicker.js, misc/colorpicker.css: 
     154    - Incorporate jQuery Color Picker by Stefan Petre. 
     155 
     1562010-02-16  Abel Cheung  <abelcheung@gmail.com> 
     157 
     158    * notation/{abc,lilypond,mup,pmw}.php: 
     159    - (define_setting_type): Fix incorrect syntax causing failure during 
     160      plugin activation. 
     161 
     1622010-02-16  Abel Cheung  <abelcheung@gmail.com> 
     163 
     164    * scorerender-admin.php: 
     165    - (scorerender_admin_menu): Simplify admin page URL. 
     166    - (scorerender_settings_link): New func, add 'Settings' link beside 
     167      Activate/Deactivate links in plugin admin page. 
     168 
     1692010-02-16  Abel Cheung  <abelcheung@gmail.com> 
     170 
     171    * notation/*.php: 
     172    - Point notation links to official page instead. 
     173 
     1742010-02-16  Abel Cheung  <abelcheung@gmail.com> 
     175 
     176    * wp-scorerender.php: 
     177    - Don't add any hook in admin page. 
     178 
     1792010-02-16  Abel Cheung  <abelcheung@gmail.com> 
     180 
     181    * notation/lilypond.php: 
     182    - Precisely determine the version that corresponds to the safe mode 
     183      option change. 
     184 
     1852010-02-12  Abel Cheung  <abelcheung@gmail.com> 
     186 
     187    * notation/lilypond.php: 
     188    - (conversion_step1) Yet another fix for lilypond invocation. Safe 
     189      mode is there after all. 
     190 
     1912010-02-12  Abel Cheung  <abelcheung@gmail.com> 
     192 
     193    * *.php, notation/*.php, misc/showcode.php: 
     194    - Update copyright, switch to AGPL v3. 
     195 
     1962010-02-12  Abel Cheung  <abelcheung@gmail.com> 
     197 
     198    * misc/ZeroClipboard.js: 
     199    - Use newest upstream release, 1.0.5. 
     200 
     2012010-02-12  Abel Cheung  <abelcheung@gmail.com> 
     202 
     203    * scorerender-admin.php: 
     204    - (scorerender_admin_add_js) Rename to scorerender_admin_head(). 
     205    - Add help icon next to admin page header, and make help text foldable. 
     206 
     2072010-02-11  Abel Cheung  <abelcheung@gmail.com> 
     208 
     209    * scorerender-admin.php: 
     210    - (scorerender_admin_options) Fix incorrectly placed html tags in 
     211      admin form, add icon to admin title. 
     212 
     2132009-08-22  Abel Cheung  <abelcheung@gmail.com> 
     214 
     215    * scorerender-utils.php: 
     216    - (search_path) New func, for searching program in PATH environment 
     217      variable. 
     218    * wp-scorerender.php: 
     219    - (scorerender_get_def_settings) Move notation program searching to 
     220      each notation file. 
     221    * scorerender-class.php, notation/*.php: 
     222    - (define_setting_value) New func, for detecting notation program 
     223      location. 
     224 
     2252009-08-13  Abel Cheung  <abelcheung@gmail.com> 
     226 
     227    * notation/lilypond.php: 
     228    - (conversion_step1) Detect lilypond version and adjust command line 
     229      accordingly. Even lilypond command line options are unstable. 
     230    - (lilypond_version) New func. 
     231 
     2322009-08-08  Abel Cheung  <abelcheung@gmail.com> 
     233 
     234    * scorerender-class.php, wp-scorerender.php, scorerender-class.php: 
     235    - Completely remove any variables and admin options to check maximum 
     236      length of music fragment. This number is not useful against abuse 
     237      nor eases resource usage. 
     238 
     2392009-08-07  Abel Cheung  <abelcheung@gmail.com> 
     240 
     241    * *.php, notation/*.php: 
     242    - PHP documentation update. 
     243    * scorerender-class.php: 
     244    - Drop ERR_INTERNAL_CLASS, which is no more needed because of PHP 
     245      interface restriction. 
     246    - Drop all method declarations already existed in ScoreRender class. 
     247    * notation/mup.php, notation/abc.php: 
     248    - (set_img_width) Use existing $img_max_width directly, instead of 
     249      using new variable. 
     250 
     2512009-08-06  Abel Cheung  <abelcheung@gmail.com> 
     252 
     253    * notation/*.php: 
     254    - Fix function declaration. 
     255 
     2562009-08-06  Abel Cheung  <abelcheung@gmail.com> 
     257 
     258    * scorerender-class.php: 
     259    - Use positive numbers for error constants. 
     260    - Utilize PHP interface to make sure each notation implements all 
     261      necessary methods. 
     262    * notation/*.php: 
     263    - Utilize PHP interface. 
     264    * notation/guido.php: 
     265    - Add all dummy functions necessary for PHP interface. 
     266 
     2672009-08-04  Abel Cheung  <abelcheung@gmail.com> 
     268 
     269    * wp-scorerender.php: 
     270    - Move default setting definition to each notation file. 
     271    - (scorerender_get_def_settings) Add hook for defining default 
     272      settings. 
     273    - (scorerender_init_class, scorerender_conversion_hook) Adopt for 
     274      change of structure of $notations. 
     275    * scorerender-class.php: 
     276    - (set_img_width) Simplify string. 
     277    * notation/*.php: 
     278    - (is_notation_usable, program_setting_entry) Adopt for change of 
     279      structure of $notations. 
     280    - (define_setting_type) New func. 
     281 
     2822009-08-03  Abel Cheung  <abelcheung@gmail.com> 
     283 
     284    * wp-scorerender.php: 
     285    - scorerender_filter() -> scorerender_init_class(), better reflecting 
     286      its actual purpose. 
     287    - scorerender_do_conversion() -> scorerender_conversion_hook() 
     288    * scorerender-class.php, notation/*.php: 
     289    - (program_setting_entry): Drop $id parameter. 
     290 
     2912009-08-01  Abel Cheung  <abelcheung@gmail.com> 
     292 
     293    * scorerender-admin.php (scorerender_admin_section_prog): 
     294    - Move program settings in admin page to each notation php. 
     295    * scorerender-class.php, notation/*.php: 
     296    - (program_setting_entry) New func for generating HTML fragment for 
     297      admin page. 
     298 
     2992009-07-30  Abel Cheung  <abelcheung@gmail.com> 
     300 
     301    * wp-scorerender.php: 
     302    - Move notation data to each notation file. 
     303    * scorerender-class.php: 
     304    - Mark is_web_hosting() and is_prog_usable() as static function. 
     305    * scorerender-admin.php (scorerender_update_options): 
     306    - Move error messages and program checking to each notation file, and 
     307      use wordpress hook to execute them. 
     308    * notation/{abc,lilypond,mup,pmw}.php: 
     309    - (define_admin_messages): New func. 
     310    - (is_notation_usable): Reworked to produce error message as well. 
     311    * notation/guido.php (is_notation_usable): 
     312    - Disabled for now. 
     313 
     3142009-07-26  Abel Cheung  <abelcheung@gmail.com> 
     315 
     316    * scorerender-class.php: 
     317    - Fix program checking logic, which fails if desired matching string 
     318      is not shown on the first line of program output.  
     319 
     3202009-07-26  Abel Cheung  <abelcheung@gmail.com> 
     321 
     322    * scorerender-admin.php: 
     323    - Tweak admin page to match WP 2.8 style. 
     324    - (scorerender_get_num_of_images) Restore this func. 
     325    - (scorerender_remove_cache) Simplify check. 
     326    - (scorerender_admin_options) Fix typo causing javascript to not 
     327      included in admin page, strip redundant description. 
     328    * wp-scorerender.php: 
     329    - (transform_paths) Move to scorerender-utils.php. 
     330    - Also define notation URLs and names. 
     331 
     3322009-07-24  Abel Cheung  <abelcheung@gmail.com> 
     333 
     334    * *.php: Version bump. 
     335    * wp-scorerender.php: 
     336    - (scorerender_get_def_settings) Avoid determining program path when 
     337      just requesting variable types.  
     338 
     3392009-07-17  Abel Cheung  <abelcheung@gmail.com> 
     340 
     341    * scorerender-admin.php: 
     342    - Drop dashboard widget, which is not very useful. 
     343    - Only add javascript to ScoreRender option page but not others. 
     344 
     3452009-05-26  Abel Cheung  <abelcheung@gmail.com> 
     346 
     347    * wp-scorerender.php (scorerender_get_def_settings): 
     348    - Better auto-detection of binary locations. 
     349 
     3502009-05-09  Abel Cheung  <abelcheung@gmail.com> 
     351 
     352    * wp-scorerender.php (scorerender_process_content): 
     353    - Also show image dimension in output image tag. 
     354    - Always use \r\n as line break when showing image code, otherwise 
     355      copy and paste can be problematic under Windows. 
     356    * scorerender-class.php, wp-scorerender.php: 
     357    - Completely remove transparency option, which is not optional now. 
     358 
     3592009-05-07  Abel Cheung  <abelcheung@gmail.com> 
     360 
     361    * scorerender*.php: 
     362    - Update copyright and version. 
     363 
     364    * scorerender-admin.php: 
     365    - Drop transparency option in admin page. 
     366    - Change admin page to match WordPress 2.7 style, and use jQuery. 
     367 
    1368=== ScoreRender 0.3.0 === 
    23692009-04-30  Abel Cheung  <abelcheung@gmail.com> 
  • scorerender/trunk/misc/ZeroClipboard.js

    r114489 r209432  
    44var ZeroClipboard = { 
    55     
    6     version: "1.0.4", 
     6    version: "1.0.5", 
    77    clients: {}, // registered upload clients on page, indexed by id 
    88    moviePath: 'ZeroClipboard.swf', // URL to movie 
     
    1818            thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; }; 
    1919            thingy.removeClass = function(name) { 
    20                 this.className = this.className.replace( new RegExp("\\s*" + name + "\\s*"), " ").replace(/^\s+/, '').replace(/\s+$/, ''); 
     20                this.className = this.className.replace( new RegExp("(^|\\s+)" + name + "(\\s+|$)"), "").replace(/^\s+|\s+$/g, ''); 
    2121            }; 
    2222            thingy.hasClass = function(name) { 
    2323                return !!this.className.match( new RegExp("\\s*" + name + "\\s*") ); 
    24             } 
     24            }; 
    2525        } 
    2626        return thingy; 
     
    4545    }, 
    4646     
    47     getDOMObjectPosition: function(obj) { 
     47    getDOMObjectPosition: function(obj, stopObj) { 
    4848        // get absolute coordinates for dom element 
    4949        var info = { 
     
    5454        }; 
    5555 
    56         while (obj) { 
     56        while (obj && (obj != stopObj)) { 
    5757            info.left += obj.offsetLeft; 
    5858            info.top += obj.offsetTop; 
     
    8989    handlers: null, // user event handlers 
    9090     
    91     glue: function(elem) { 
     91    glue: function(elem, appendElem, stylesToAdd) { 
    9292        // glue to DOM element 
    9393        // elem can be ID or actual DOM element object 
     
    9797        var zIndex = 99; 
    9898        if (this.domElement.style.zIndex) { 
    99             zIndex = parseInt(this.domElement.style.zIndex) + 1; 
     99            zIndex = parseInt(this.domElement.style.zIndex, 10) + 1; 
     100        } 
     101         
     102        if (typeof(appendElem) == 'string') { 
     103            appendElem = ZeroClipboard.$(appendElem); 
     104        } 
     105        else if (typeof(appendElem) == 'undefined') { 
     106            appendElem = document.getElementsByTagName('body')[0]; 
    100107        } 
    101108         
    102109        // find X/Y position of domElement 
    103         var box = ZeroClipboard.getDOMObjectPosition(this.domElement); 
     110        var box = ZeroClipboard.getDOMObjectPosition(this.domElement, appendElem); 
    104111         
    105112        // create floating DIV above element 
     
    113120        style.zIndex = zIndex; 
    114121         
     122        if (typeof(stylesToAdd) == 'object') { 
     123            for (addedStyle in stylesToAdd) { 
     124                style[addedStyle] = stylesToAdd[addedStyle]; 
     125            } 
     126        } 
     127         
    115128        // style.backgroundColor = '#f00'; // debug 
    116129         
    117         var body = document.getElementsByTagName('body')[0]; 
    118         body.appendChild(this.div); 
     130        appendElem.appendChild(this.div); 
    119131         
    120132        this.div.innerHTML = this.getHTML( box.width, box.height ); 
  • scorerender/trunk/misc/showcode.php

    r114489 r209432  
    11<?php 
     2/* 
     3    Copyright (C) 2007, 2008, 2009, 2010 Abel Cheung 
     4 
     5    This program is free software: you can redistribute it and/or modify 
     6    it under the terms of the GNU Affero General Public License as 
     7    published by the Free Software Foundation, either version 3 of the 
     8    License, or (at your option) any later version. 
     9 
     10    This program is distributed in the hope that it will be useful, 
     11    but WITHOUT ANY WARRANTY; without even the implied warranty of 
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     13    GNU Affero General Public License for more details. 
     14 
     15    You should have received a copy of the GNU Affero General Public License 
     16    along with this program.  If not, see <http://www.gnu.org/licenses/>. 
     17*/ 
     18 
    219    // this file must be either 3 or 4 levels from WP top dir 
    320    if (file_exists ('../../../../wp-config.php')) 
  • scorerender/trunk/notation/abc.php

    r66601 r209432  
    33 * Implements rendering of ABC notation in ScoreRender. 
    44 * @package ScoreRender 
     5 * @version 0.3.50 
     6 * @author Abel Cheung <abelcheung at gmail dot com> 
     7 * @copyright Copyright (C) 2007, 2008, 2009, 2010 Abel Cheung 
     8 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU AGPL v3 
    59*/ 
    610 
     
    1014*/ 
    1115class abcRender extends ScoreRender 
     16                implements ScoreRender_Notation 
    1217{ 
    1318 
    14 private $width; 
    15  
    1619/** 
    17  * Set maximum width of generated images 
     20 * Refer to {@link ScoreRender::set_img_width() parent method} 
     21 * for more detail. 
    1822 * 
    19  * @param integer $width Maximum width of images (in pixel) 
    20  * @since 0.2.50 
     23 * Seems abcm2ps is using something like 120 dpi, 
     24 * with 72DPI the notes and letters are very thin :( 
    2125 */ 
    2226public function set_img_width ($width) 
    2327{ 
    2428    parent::set_img_width ($width); 
    25  
    26     // Seems abcm2ps is using something like 120 dpi, 
    27     // with 72DPI the notes and letters are very thin :( 
    28     $this->width = $this->img_max_width / 120; 
     29    $this->img_max_width /= 120; 
    2930} 
    3031 
    3132/** 
    32  * Refer to {@link ScoreRender::get_music_fragment() parent method} for more detail. 
     33 * Refer to {@link ScoreRender_Notation::get_music_fragment() interface method} for more detail. 
    3334 */ 
    3435public function get_music_fragment () 
     
    3637    $header = <<<EOT 
    3738%abc 
    38 %%staffwidth {$this->width}in 
     39%%staffwidth {$this->img_max_width}in 
    3940%%stretchlast no 
    4041%%leftmargin 0.2in 
     
    6768 
    6869/** 
    69  * Check if given program is abcm2ps, and whether it is usable. 
    70  * 
    71  * @param string $args A CGI-like query string containing the program to be checked. 
    72  * @uses is_prog_usable() 
    73  * @return boolean Return true if the given program is abcm2ps AND it is executable. 
     70 * Refer to {@link ScoreRender_Notation::is_notation_usable() interface method} 
     71 * for more detail. 
     72 * @uses ScoreRender::is_prog_usable() 
    7473 */ 
    75 public function is_notation_usable ($args = '') 
     74public static function is_notation_usable ($errmsgs, $opt) 
    7675{ 
    77     wp_parse_str ($args, $r); 
    78     extract ($r, EXTR_SKIP); 
    79     return parent::is_prog_usable ('abcm2ps', $prog, '-V'); 
     76    global $notations; 
     77 
     78    $ok = true; 
     79    foreach ($notations['abc']['progs'] as $setting_name => $program) 
     80        if ( ! empty ($opt[$setting_name]) && ! parent::is_prog_usable ( 
     81            $program['test_output'], $opt[$setting_name], $program['test_arg']) ) 
     82                $ok = false; 
     83             
     84    if (!$ok) $errmsgs[] = 'abcm2ps_bin_problem'; 
     85} 
     86 
     87/** 
     88 * Refer to {@link ScoreRender_Notation::define_admin_messages() interface method} 
     89 * for more detail. 
     90 */ 
     91public static function define_admin_messages ($adm_msgs) 
     92{ 
     93    global $notations; 
     94 
     95    $adm_msgs['abcm2ps_bin_problem'] = array ( 
     96        'level' => MSG_WARNING, 
     97        'content' => sprintf (__('%s notation support may not work, because dependent program failed checking.', TEXTDOMAIN), $notations['abc']['name']) 
     98    ); 
     99} 
     100 
     101/** 
     102 * Refer to {@link ScoreRender_Notation::program_setting_entry() interface method} 
     103 * for more detail. 
     104 */ 
     105public static function program_setting_entry ($output) 
     106{ 
     107    global $notations; 
     108 
     109    foreach ($notations['abc']['progs'] as $setting_name => $program) 
     110        $output .= parent::program_setting_entry ( 
     111            $program['prog_name'], $setting_name); 
     112    return $output; 
     113} 
     114 
     115/** 
     116 * Refer to {@link ScoreRender_Notation::define_setting_type() interface method} 
     117 * for more detail. 
     118 */ 
     119public static function define_setting_type ($settings) 
     120{ 
     121    global $notations; 
     122 
     123    foreach ($notations['abc']['progs'] as $key => $value) 
     124        $settings[$key] = $value; 
     125} 
     126 
     127/** 
     128 * Refer to {@link ScoreRender_Notation::define_setting_value() interface method} 
     129 * for more detail. 
     130 */ 
     131public static function define_setting_value ($settings) 
     132{ 
     133    global $notations; 
     134 
     135    $binary_name = $notations['abc']['progs']['ABCM2PS_BIN']['prog_name']; 
     136    if ( is_windows() ) $binary_name .= '.exe'; 
     137    $fullpath = ''; 
     138 
     139    if ( is_windows() ) 
     140    { 
     141        $fullpath = search_path ($binary_name); 
     142        if ( !$fullpath && function_exists ('glob') ) 
     143        { 
     144            $fullpath = glob ("C:\\Program Files\\*\\" . $binary_name); 
     145            $fullpath = empty ($fullpath) ? '' : $fullpath[0]; 
     146        } 
     147    } 
     148    else 
     149    { 
     150        if ( function_exists ('shell_exec') ) 
     151            $fullpath = shell_exec ('which ' . $binary_name); 
     152        else 
     153            $fullpath = search_path ($binary_name); 
     154    } 
     155 
     156    $settings['ABCM2PS_BIN']['value'] = empty ($fullpath) ? '' : $fullpath; 
    80157} 
    81158 
    82159} // end of class 
    83160 
     161 
     162$notations['abc'] = array ( 
     163    'name'        => 'ABC', 
     164    'url'         => 'http://scorerender.abelcheung.org/demo/demo-abc/', 
     165    'regex'       => '~\[abc\](.*?)\[/abc\]~si', 
     166    'starttag'    => '[abc]', 
     167    'endtag'      => '[/abc]', 
     168    'classname'   => 'abcRender', 
     169    'progs'       => array ( 
     170        'ABCM2PS_BIN' => array ( 
     171            'prog_name' => 'abcm2ps', 
     172            'type'      => 'prog', 
     173            'value'     => '', 
     174            'test_arg'  => '-V', 
     175            'test_output' => 'abcm2ps', 
     176        ), 
     177    ), 
     178); 
     179 
     180 
     181add_action ('scorerender_define_adm_msgs', 
     182    array( 'abcRender', 'define_admin_messages' ) ); 
     183 
     184add_action ('scorerender_check_notation_progs', 
     185    array( 'abcRender', 'is_notation_usable' ), 10, 2 ); 
     186 
     187add_filter ('scorerender_prog_and_file_loc', 
     188    array( 'abcRender', 'program_setting_entry' ) ); 
     189 
     190add_filter ('scorerender_define_setting_type', 
     191    array( 'abcRender', 'define_setting_type' ) ); 
     192 
     193add_filter ('scorerender_define_setting_value', 
     194    array( 'abcRender', 'define_setting_value' ) ); 
    84195?> 
  • scorerender/trunk/notation/guido.php

    r66601 r209432  
    33 * Implements rendering of GUIDO notation in ScoreRender. 
    44 * @package ScoreRender 
     5 * @version 0.3.50 
     6 * @author Abel Cheung <abelcheung at gmail dot com> 
     7 * @copyright Copyright (C) 2007, 2008, 2009, 2010 Abel Cheung 
     8 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU AGPL v3 
    59*/ 
    610 
     
    1014*/ 
    1115class guidoRender extends ScoreRender 
     16                  implements ScoreRender_Notation 
    1217{ 
    1318 
     
    5661 * @return boolean Return true if remote URL can be fopen'ed. 
    5762 */ 
     63/* 
    5864public function is_notation_usable ($args = '') 
    5965{ 
    6066    return ini_get('allow_url_fopen'); 
    6167} 
     68 */ 
     69 
     70/** 
     71 * @ignore 
     72 */ 
     73public static function is_notation_usable ($errmsgs, $opt) {} 
     74 
     75/** 
     76 * @ignore 
     77 */ 
     78public static function define_admin_messages ($adm_msgs) {} 
     79 
     80/** 
     81 * @ignore 
     82 */ 
     83public static function program_setting_entry ($output) {} 
     84 
     85/** 
     86 * @ignore 
     87 */ 
     88public static function define_setting_type ($settings) {} 
     89 
     90/** 
     91 * @ignore 
     92 */ 
     93public static function define_setting_value ($settings) {} 
    6294 
    6395} // end of class 
    6496 
     97 
     98$notations['guido'] = array ( 
     99    'name'        => 'GUIDO', 
     100    'url'         => 'http://scorerender.abelcheung.org/demo/demo-guido/', 
     101    'regex'       => '~\[guido\](.*?)\[/guido\]~si', 
     102    'starttag'    => '[guido]', 
     103    'endtag'      => '[/guido]', 
     104    'classname'   => 'guidoRender', 
     105    'progs'       => array (), 
     106); 
     107 
    65108?> 
  • scorerender/trunk/notation/lilypond.php

    r66601 r209432  
    11<?php 
    2 /* 
    3  Mostly based on class.lilypondrender.inc.php from FigureRender 
    4  Chris Lamb <chris@chris-lamb.co.uk> 
    5  10th April 2006 
    6 */ 
    7  
    82/** 
    93 * Implements rendering of Lilypond notation in ScoreRender. 
    104 * @package ScoreRender 
     5 * @version 0.3.50 
     6 * @author Abel Cheung <abelcheung at gmail dot com> 
     7 * @copyright Copyright (C) 2007, 2008, 2009, 2010 Abel Cheung 
     8 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU AGPL v3 
    119*/ 
    1210 
     
    1614*/ 
    1715class lilypondRender extends ScoreRender 
    18 { 
    19  
    20 /** 
    21  * Refer to {@link ScoreRender::get_music_fragment() parent method} for more detail. 
     16                     implements ScoreRender_Notation 
     17{ 
     18 
     19/** 
     20 * Refer to {@link ScoreRender_Notation::get_music_fragment() interface method} 
     21 * for more detail. 
    2222 */ 
    2323public function get_music_fragment () 
     
    4646 
    4747/** 
    48  * Refer to {@link ScoreRender::conversion_step1() parent method} for more detail. 
     48 * Determine LilyPond version 
     49 * @param string $lilypond The path of lilypond program 
     50 * @return string|boolean The version number string if it can be determined, otherwise FALSE  
     51 */ 
     52public static function lilypond_version ($lilypond) 
     53{ 
     54    if ( !function_exists ('exec') ) return FALSE; 
     55 
     56    exec ("\"$lilypond\" -v 2>&1", $output, $retval); 
     57     
     58    if ( empty ($output) ) return FALSE; 
     59    if ( !preg_match('/^gnu lilypond (\d+\.\d+\.\d+)/i', $output[0], $matches) ) return FALSE; 
     60    return $matches[1]; 
     61} 
     62 
     63/** 
     64 * Refer to {@link ScoreRender::conversion_step1() parent method} 
     65 * for more detail. 
    4966 */ 
    5067protected function conversion_step1 ($input_file, $intermediate_image) 
    5168{ 
    52     /* lilypond adds .ps extension by itself */ 
    53     $cmd = sprintf ('"%s" --safe --ps --output "%s" "%s"', 
     69    $safemode = ''; 
     70    /* LilyPond SUCKS unquestionably. On 2.8 safe mode is triggered by "--safe" option, 
     71     * on 2.10.x it becomes "--safe-mode", and on 2.12.x that"s "-dsafe"! 
     72     */ 
     73    if ( false !== ( $lilypond_ver = self::lilypond_version ($this->mainprog) ) ) 
     74        if ( version_compare ($lilypond_ver, '2.11.11', '<') ) 
     75            $safemode = '-s'; 
     76        else 
     77            $safemode = '-dsafe'; 
     78     
     79    /* lilypond adds .ps extension by itself, sucks for temp file generation */ 
     80    $cmd = sprintf ('"%s" %s --ps --output "%s" "%s"', 
    5481        $this->mainprog, 
     82        $safemode, 
    5583        dirname($intermediate_image) . DIRECTORY_SEPARATOR . basename($intermediate_image, ".ps"), 
    5684        $input_file); 
     
    6290 
    6391/** 
    64  * Refer to {@link ScoreRender::conversion_step2() parent method} for more detail. 
     92 * Refer to {@link ScoreRender::conversion_step2() parent method} 
     93 * for more detail. 
    6594 */ 
    6695protected function conversion_step2 ($intermediate_image, $final_image) 
     
    73102 
    74103/** 
    75  * Check if given program is LilyPond, and whether it is usable. 
    76  * 
    77  * @param string $args A CGI-like query string containing the program to be checked. 
    78  * @uses is_prog_usable() 
    79  * @return boolean Return true if the given program is LilyPond AND it is executable. 
    80  */ 
    81 public function is_notation_usable ($args = '') 
    82 { 
    83     wp_parse_str ($args, $r); 
    84     extract ($r, EXTR_SKIP); 
    85     return parent::is_prog_usable ('GNU LilyPond', $prog, '--version'); 
     104 * Refer to {@link ScoreRender_Notation::is_notation_usable() interface method} 
     105 * for more detail. 
     106 * @uses ScoreRender::is_prog_usable() 
     107 */ 
     108public static function is_notation_usable ($errmsgs, $opt) 
     109{ 
     110    global $notations; 
     111 
     112    $ok = true; 
     113    foreach ($notations['lilypond']['progs'] as $setting_name => $program) 
     114        if ( ! empty ($opt[$setting_name]) && ! parent::is_prog_usable ( 
     115            $program['test_output'], $opt[$setting_name], $program['test_arg']) ) 
     116                $ok = false; 
     117             
     118    if (!$ok) $errmsgs[] = 'lilypond_bin_problem'; 
     119} 
     120 
     121/** 
     122 * Refer to {@link ScoreRender_Notation::define_admin_messages() interface method} 
     123 * for more detail. 
     124 */ 
     125public static function define_admin_messages ($adm_msgs) 
     126{ 
     127    global $notations; 
     128 
     129    $adm_msgs['lilypond_bin_problem'] = array ( 
     130        'level' => MSG_WARNING, 
     131        'content' => sprintf (__('%s notation support may not work, because dependent program failed checking.', TEXTDOMAIN), $notations['lilypond']['name']) 
     132    ); 
     133} 
     134 
     135/** 
     136 * Refer to {@link ScoreRender_Notation::program_setting_entry() interface method} 
     137 * for more detail. 
     138 */ 
     139public static function program_setting_entry ($output) 
     140{ 
     141    global $notations; 
     142 
     143    foreach ($notations['lilypond']['progs'] as $setting_name => $program) 
     144        $output .= parent::program_setting_entry ( 
     145            $program['prog_name'], $setting_name); 
     146    return $output; 
     147} 
     148 
     149/** 
     150 * Refer to {@link ScoreRender_Notation::define_setting_type() interface method} 
     151 * for more detail. 
     152 */ 
     153public static function define_setting_type ($settings) 
     154{ 
     155    global $notations; 
     156 
     157    foreach ($notations['lilypond']['progs'] as $key => $value) 
     158        $settings[$key] = $value; 
     159} 
     160 
     161/** 
     162 * Refer to {@link ScoreRender_Notation::define_setting_value() interface method} 
     163 * for more detail. 
     164 */ 
     165public static function define_setting_value ($settings) 
     166{ 
     167    global $notations; 
     168 
     169    $binary_name = $notations['lilypond']['progs']['LILYPOND_BIN']['prog_name']; 
     170    if ( is_windows() ) $binary_name .= '.exe'; 
     171    $fullpath = ''; 
     172 
     173    if ( is_windows() ) 
     174    { 
     175        $fullpath = search_path ($binary_name); 
     176        if ( !$fullpath && function_exists ('glob') ) 
     177        { 
     178            $fullpath = glob ("C:\\Program Files\\*\\usr\\bin\\" . $binary_name); 
     179            $fullpath = empty ($fullpath) ? '' : $fullpath[0]; 
     180        } 
     181    } 
     182    else 
     183    { 
     184        if ( function_exists ('shell_exec') ) 
     185            $fullpath = shell_exec ('which ' . $binary_name); 
     186        else 
     187            $fullpath = search_path ($binary_name); 
     188    } 
     189 
     190    $settings['LILYPOND_BIN']['value'] = empty ($fullpath) ? '' : $fullpath; 
    86191} 
    87192 
    88193} // end of class 
    89194 
     195 
     196$notations['lilypond'] = array ( 
     197    'name'        => 'LilyPond', 
     198    'url'         => 'http://scorerender.abelcheung.org/demo/demo-lilypond/', 
     199    'regex'       => '~\[lilypond\](.*?)\[/lilypond\]~si', 
     200    'starttag'    => '[lilypond]', 
     201    'endtag'      => '[/lilypond]', 
     202    'classname'   => 'lilypondRender', 
     203    'progs'       => array ( 
     204        'LILYPOND_BIN' => array ( 
     205            'prog_name' => 'lilypond', 
     206            'type'      => 'prog', 
     207            'value'     => '', 
     208            'test_arg'  => '--version', 
     209            'test_output' => 'GNU LilyPond', 
     210        ), 
     211    ), 
     212); 
     213 
     214 
     215add_action ('scorerender_define_adm_msgs', 
     216    array( 'lilypondRender', 'define_admin_messages' ) ); 
     217 
     218add_action ('scorerender_check_notation_progs', 
     219    array( 'lilypondRender', 'is_notation_usable' ), 10, 2 ); 
     220 
     221add_filter ('scorerender_prog_and_file_loc', 
     222    array( 'lilypondRender', 'program_setting_entry' ) ); 
     223 
     224add_filter ('scorerender_define_setting_type', 
     225    array( 'lilypondRender', 'define_setting_type' ) ); 
     226 
     227add_filter ('scorerender_define_setting_value', 
     228    array( 'lilypondRender', 'define_setting_value' ) ); 
    90229?> 
  • scorerender/trunk/notation/mup.php

    r114489 r209432  
    33 * Implements rendering of Mup notation in ScoreRender. 
    44 * @package ScoreRender 
     5 * @version 0.3.50 
     6 * @author Abel Cheung <abelcheung at gmail dot com> 
     7 * @copyright Copyright (C) 2007, 2008, 2009, 2010 Abel Cheung 
     8 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU AGPL v3 
    59*/ 
    610 
     
    1014*/ 
    1115class mupRender extends ScoreRender 
    12 { 
    13  
    14 private $width; 
    15  
    16 /** 
    17  * @var string $magic_file Location of magic file used by Mup 
     16                implements ScoreRender_Notation 
     17{ 
     18 
     19/** 
     20 * Registration key for MUP. 
     21 * 
    1822 * @access private 
    1923 */ 
    20 private $magic_file; 
    21  
     24private $reg_key; 
     25 
     26/** 
     27 * Class constructor, for adding wordpress hook to perform notation specific 
     28 * setup 
     29 * @uses set_notation_action() 
     30 * @access private 
     31 */ 
    2232function __construct () 
    2333{ 
    24     add_action ('sr_set_class_variable', array (&$this, 'set_magic_file_hook')); 
    25 } 
    26  
    27 /** 
    28  * Set maximum width of generated images 
    29  * 
    30  * @param integer $width Maximum width of images (in pixel) 
    31  * @since 0.2.50 
     34    add_action ('sr_set_class_variable', array (&$this, 'set_notation_action')); 
     35} 
     36 
     37/** 
     38 * Refer to {@link ScoreRender::set_img_width() parent method} 
     39 * for more detail. 
     40 * For Mup notation, it is more convenient to use inch as unit 
    3241 */ 
    3342public function set_img_width ($width) 
    3443{ 
    3544    parent::set_img_width ($width); 
    36     $this->width = $this->img_max_width / DPI; 
    37 } 
    38  
    39 /** 
    40  * Set the location of magic file 
    41  * 
    42  * @param string $file Full path of magic file 
    43  * @since 0.2.50 
    44  */ 
    45 public function set_magic_file ($file) 
    46 { 
    47     $this->magic_file = $file; 
     45    $this->img_max_width /= DPI; 
    4846} 
    4947 
     
    5149 * Checks if given content is invalid or dangerous content 
    5250 * 
    53  * @param string $input 
    5451 * @return boolean True if content is deemed safe 
    5552 */ 
     
    6966 
    7067/** 
    71  * Refer to {@link ScoreRender::get_music_fragment() parent method} for more detail. 
     68 * Refer to {@link ScoreRender_Notation::get_music_fragment() interface method} 
     69 * for more detail. 
    7270 */ 
    7371public function get_music_fragment () 
     
    8078topmargin = 0 
    8179bottommargin = 0 
    82 pagewidth = {$this->width} 
     80pagewidth = {$this->img_max_width} 
    8381label = "" 
    8482EOD; 
     
    8785 
    8886/** 
    89  * Refer to {@link ScoreRender::conversion_step1() parent method} for more detail. 
     87 * Refer to {@link ScoreRender::conversion_step1() parent method} 
     88 * for more detail. 
     89 * 
     90 * @uses is_windows() 
     91 * @uses $temp_dir For storing temporary copy of magic file 
    9092 */ 
    9193protected function conversion_step1 ($input_file, $intermediate_image) 
    9294{ 
    93     /* Mup requires a magic file before it is usable. 
    94        On Unix this file is named ".mup", and must reside in $HOME or current working directory. 
    95        On Windows / DOS, it is named "mup.ok" instead, and located in current working directory or same location as mup.exe do. 
    96        It must be present even if not registered, otherwise mup refuse to render anything. 
    97        Even worse, the exist status in this case is 0, so _exec() succeeds yet no postscript is rendered. */ 
    98  
    99     if (is_windows()) 
    100         $temp_magic_file = $this->temp_dir . '\mup.ok'; 
    101     else 
    102         $temp_magic_file = $this->temp_dir . '/.mup'; 
     95    /* 
     96     * Mup requires a magic file before it is usable. 
     97     * On Unix this file is named ".mup", and must reside in $HOME or 
     98     * current working directory.  On Windows/DOS, it is named "mup.ok" 
     99     * instead, and located in current working directory or same location 
     100     * as mup.exe do. 
     101     * It must be present even if not registered, otherwise mup refuse to 
     102     * render anything.  Even worse, the exist status in this case is 0, 
     103     * so _exec() succeeds yet no postscript is rendered. 
     104     */ 
     105    $temp_magic_file = $this->temp_dir . ( is_windows() ? '\mup.ok' : '/.mup' ); 
    103106     
    104     if (!file_exists($temp_magic_file)) 
    105     { 
    106         if (is_readable($this->magic_file)) 
    107             copy($this->magic_file, $temp_magic_file); 
    108         else 
    109             touch ($temp_magic_file); 
    110     } 
     107    if ( ! file_exists ($temp_magic_file) ) 
     108        file_put_contents ( $temp_magic_file, $this->reg_key ); 
    111109 
    112110    /* mup forces this kind of crap */ 
     
    131129    // FIXME: mind boggling exercise: why ImageMagick identifies PostScript produced by Mup as having 
    132130    // transparency on Windows, yet otherwise on Linux? 
    133     return parent::conversion_step2 ($intermediate_image, $final_image, is_windows()); 
    134 } 
    135  
    136  
    137 /** 
    138  * Check if given program is Mup, and whether it is usable. 
    139  * 
    140  * @param string $args A CGI-like query string containing the program to be checked. 
    141  * @uses is_prog_usable() 
    142  * @return boolean Return true if the given program is Mup AND it is executable. 
    143  */ 
    144 public function is_notation_usable ($args = '') 
    145 { 
    146     wp_parse_str ($args, $r); 
    147     extract ($r, EXTR_SKIP); 
    148     return parent::is_prog_usable ('Arkkra Enterprises', $prog, '-v'); 
    149 } 
    150  
    151 /** 
    152  * Set the location of magic file 
    153  * This is not supposed to be called directly; it is used as a 
    154  * WordPress action hook instead. 
     131    // FIXME: 2. more exercise: when is it interpreted as having transparency on Linux too? 
     132    return parent::conversion_step2 ($intermediate_image, $final_image, true); 
     133} 
     134 
     135 
     136/** 
     137 * Perform any notation specific action 
    155138 * 
    156139 * {@internal OK, I cheated. Shouldn't have been leaking external 
     
    160143 * @since 0.2.50 
    161144 */ 
    162 public function set_magic_file_hook ($options) 
    163 { 
    164     if (isset ($options['MUP_MAGIC_FILE'])) 
    165         $this->set_magic_file ($options['MUP_MAGIC_FILE']); 
     145public function set_notation_action ($options) 
     146{ 
     147    if ( isset ( $options['MUP_REG_KEY'] ) ) 
     148        $this->reg_key = $options['MUP_REG_KEY']; 
     149} 
     150 
     151/** 
     152 * Refer to {@link ScoreRender_Notation::is_notation_usable() interface method} 
     153 * for more detail. 
     154 * @uses ScoreRender::is_prog_usable() 
     155 */ 
     156public static function is_notation_usable ($errmsgs, $opt) 
     157{ 
     158    global $notations; 
     159 
     160    $ok = true; 
     161    foreach ($notations['mup']['progs'] as $setting_name => $program) 
     162        if ( ! empty ($opt[$setting_name]) && ! parent::is_prog_usable ( 
     163            $program['test_output'], $opt[$setting_name], $program['test_arg']) ) 
     164                $ok = false; 
     165             
     166    if (!$ok) $errmsgs[] = 'mup_bin_problem'; 
     167} 
     168 
     169/** 
     170 * Refer to {@link ScoreRender_Notation::define_admin_messages() interface method} 
     171 * for more detail. 
     172 */ 
     173public static function define_admin_messages ($adm_msgs) 
     174{ 
     175    global $notations; 
     176 
     177    $adm_msgs['mup_bin_problem'] = array ( 
     178        'level' => MSG_WARNING, 
     179        'content' => sprintf (__('%s notation support may not work, because dependent program failed checking.', TEXTDOMAIN), $notations['mup']['name']) 
     180    ); 
     181} 
     182 
     183/** 
     184 * Refer to {@link ScoreRender_Notation::program_setting_entry() interface method} 
     185 * for more detail. 
     186 */ 
     187public static function program_setting_entry ($output) 
     188{ 
     189    global $notations; 
     190 
     191    foreach ($notations['mup']['progs'] as $setting_name => $program) 
     192        $output .= parent::program_setting_entry ( 
     193            $program['prog_name'], $setting_name); 
     194 
     195    $output .= parent::program_setting_entry ( 
     196        '', 'MUP_REG_KEY', 
     197        sprintf (__('%s registration key:', TEXTDOMAIN), '<code>mup</code>'), 
     198        sprintf (__('Leave it empty if you have not <a href="%s">registered</a> Mup.', TEXTDOMAIN), 
     199            'http://www.arkkra.com/doc/faq.html#payment') 
     200    ); 
     201    return $output; 
     202} 
     203 
     204/** 
     205 * Refer to {@link ScoreRender_Notation::define_setting_type() interface method} 
     206 * for more detail. 
     207 */ 
     208public static function define_setting_type ($settings) 
     209{ 
     210    global $notations; 
     211 
     212    foreach ($notations['mup']['progs'] as $key => $value) 
     213        $settings[$key] = $value; 
     214} 
     215 
     216/** 
     217 * Refer to {@link ScoreRender_Notation::define_setting_value() interface method} 
     218 * for more detail. 
     219 */ 
     220public static function define_setting_value ($settings) 
     221{ 
     222    global $notations; 
     223 
     224    $binary_name = $notations['mup']['progs']['MUP_BIN']['prog_name']; 
     225    if ( is_windows() ) $binary_name .= '.exe'; 
     226    $fullpath = ''; 
     227 
     228    if ( is_windows() ) 
     229    { 
     230        $fullpath = search_path ($binary_name); 
     231        if ( !$fullpath && function_exists ('glob') ) 
     232        { 
     233            $fullpath = glob ("C:\\Program Files\\*\\" . $binary_name); 
     234            $fullpath = empty ($fullpath) ? '' : $fullpath[0]; 
     235        } 
     236    } 
     237    else 
     238    { 
     239        if ( function_exists ('shell_exec') ) 
     240            $fullpath = shell_exec ('which ' . $binary_name); 
     241        else 
     242            $fullpath = search_path ($binary_name); 
     243    } 
     244 
     245    $settings['MUP_BIN']['value'] = empty ($fullpath) ? '' : $fullpath; 
    166246} 
    167247 
    168248}  // end of class 
    169249 
     250 
     251$notations['mup'] = array ( 
     252    'name'        => 'Mup', 
     253    'url'         => 'http://scorerender.abelcheung.org/demo/demo-mup/', 
     254    'regex'       => '~\[mup\](.*?)\[/mup\]~si', 
     255    'starttag'    => '[mup]', 
     256    'endtag'      => '[/mup]', 
     257    'classname'   => 'mupRender', 
     258    'progs'       => array ( 
     259        'MUP_BIN' => array ( 
     260            'prog_name' => 'mup', 
     261            'type'      => 'prog', 
     262            'value'     => '', 
     263            'test_arg'  => '-v', 
     264            'test_output' => 'Arkkra Enterprises', 
     265        ), 
     266    ), 
     267); 
     268 
     269 
     270add_action ('scorerender_define_adm_msgs', 
     271    array( 'mupRender', 'define_admin_messages' ) ); 
     272 
     273add_action ('scorerender_check_notation_progs', 
     274    array( 'mupRender', 'is_notation_usable' ), 10, 2 ); 
     275 
     276add_filter ('scorerender_prog_and_file_loc', 
     277    array( 'mupRender', 'program_setting_entry' ) ); 
     278 
     279add_filter ('scorerender_define_setting_type', 
     280    array( 'mupRender', 'define_setting_type' ) ); 
     281 
     282add_filter ('scorerender_define_setting_value', 
     283    array( 'mupRender', 'define_setting_value' ) ); 
    170284?> 
  • scorerender/trunk/notation/pmw.php

    r114489 r209432  
    33 * Implements rendering of Philip's Music Writer notation in ScoreRender. 
    44 * @package ScoreRender 
     5 * @version 0.3.50 
     6 * @author Abel Cheung <abelcheung at gmail dot com> 
     7 * @copyright Copyright (C) 2008, 2009, 2010 Abel Cheung 
     8 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU AGPL v3 
    59*/ 
    610 
     
    1014*/ 
    1115class pmwRender extends ScoreRender 
     16                implements ScoreRender_Notation 
    1217{ 
    1318 
    1419/** 
    15  * Refer to {@link ScoreRender::get_music_fragment() parent method} for more detail. 
     20 * Refer to {@link ScoreRender_Notation::get_music_fragment() interface method} 
     21 * for more detail. 
     22 * 
     23 * @uses $img_max_width 
     24 * @uses $_input 
    1625 */ 
    1726public function get_music_fragment () 
     
    3140/** 
    3241 * Refer to {@link ScoreRender::conversion_step1() parent method} for more detail. 
     42 * 
     43 * @uses $mainprog 
     44 * @uses _exec() 
    3345 */ 
    3446protected function conversion_step1 ($input_file, $intermediate_image) 
    3547{ 
    36     $cmd = sprintf ('"%s" -includefont -o "%s" "%s"', 
     48    $cmd = sprintf ('"%s" -norc -includefont -o "%s" "%s"', 
    3749            $this->mainprog, 
    3850            $intermediate_image, $input_file); 
     
    5365    // in PostScript produced by PMW. 
    5466    return parent::conversion_step2 ($intermediate_image, 
    55         $final_image, FALSE, '-page a3'); 
     67        $final_image, true, '-page a3'); 
    5668} 
    5769 
    5870/** 
    59  * Check if given program is Philip's Music Writer, and whether it is usable. 
    60  * 
    61  * @param string $args A CGI-like query string containing the program to be checked. 
     71 * Refer to {@link ScoreRender_Notation::is_notation_usable() interface method} 
     72 * for more detail. 
    6273 * @uses is_prog_usable() 
    63  * @return boolean Return true if the given program is pmw AND it is executable. 
    6474 */ 
    65 public function is_notation_usable ($args = '') 
     75public static function is_notation_usable ($errmsgs, $opt) 
    6676{ 
    67     wp_parse_str ($args, $r); 
    68     extract ($r, EXTR_SKIP); 
    69     return parent::is_prog_usable ('PMW version', $prog, '-V'); 
     77    global $notations; 
     78 
     79    $ok = true; 
     80    foreach ($notations['pmw']['progs'] as $setting_name => $program) 
     81        if ( ! empty ($opt[$setting_name]) && ! parent::is_prog_usable ( 
     82            $program['test_output'], $opt[$setting_name], $program['test_arg']) ) 
     83                $ok = false; 
     84             
     85    if (!$ok) $errmsgs[] = 'pmw_bin_problem'; 
     86} 
     87 
     88/** 
     89 * Refer to {@link ScoreRender_Notation::define_admin_messages() interface method} 
     90 * for more detail. 
     91 */ 
     92public static function define_admin_messages ($adm_msgs) 
     93{ 
     94    global $notations; 
     95 
     96    $adm_msgs['pmw_bin_problem'] = array ( 
     97        'level' => MSG_WARNING, 
     98        'content' => sprintf (__('%s notation support may not work, because dependent program failed checking.', TEXTDOMAIN), $notations['pmw']['name']) 
     99    ); 
     100} 
     101 
     102/** 
     103 * Refer to {@link ScoreRender_Notation::program_setting_entry() interface method} 
     104 * for more detail. 
     105 */ 
     106public static function program_setting_entry ($output) 
     107{ 
     108    global $notations; 
     109 
     110    foreach ($notations['pmw']['progs'] as $setting_name => $program) 
     111        $output .= parent::program_setting_entry ( 
     112            $program['prog_name'], $setting_name); 
     113    return $output; 
     114} 
     115 
     116/** 
     117 * Refer to {@link ScoreRender_Notation::define_setting_type() interface method} 
     118 * for more detail. 
     119 */ 
     120public static function define_setting_type ($settings) 
     121{ 
     122    global $notations; 
     123 
     124    foreach ($notations['pmw']['progs'] as $key => $value) 
     125        $settings[$key] = $value; 
     126} 
     127 
     128/** 
     129 * Refer to {@link ScoreRender_Notation::define_setting_value() interface method} 
     130 * for more detail. 
     131 */ 
     132public static function define_setting_value ($settings) 
     133{ 
     134    global $notations; 
     135 
     136    $binary_name = $notations['pmw']['progs']['PMW_BIN']['prog_name']; 
     137    if ( is_windows() ) $binary_name .= '.exe'; 
     138    $fullpath = ''; 
     139 
     140    // PMW doesn't even have public available Win32 binary, perhaps 
     141    // somebody might be able to compile it with MinGW? 
     142    if ( !is_windows() ) 
     143    { 
     144        if ( function_exists ('shell_exec') ) 
     145            $fullpath = shell_exec ('which ' . $binary_name); 
     146        else 
     147            $fullpath = search_path ($binary_name); 
     148    } 
     149 
     150    $settings['PMW_BIN']['value'] = empty ($fullpath) ? '' : $fullpath; 
    70151} 
    71152 
    72153} // end of class 
    73154 
     155 
     156$notations['pmw'] = array ( 
     157    'name'        => "Philip's Music Writer", 
     158    'url'         => 'http://scorerender.abelcheung.org/demo/demo-pmw/', 
     159    'regex'       => '~\[pmw\](.*?)\[/pmw\]~si', 
     160    'starttag'    => '[pmw]', 
     161    'endtag'      => '[/pmw]', 
     162    'classname'   => 'pmwRender', 
     163    'progs'       => array ( 
     164        'PMW_BIN' => array ( 
     165            'prog_name' => 'pmw', 
     166            'type'      => 'prog', 
     167            'value'     => '', 
     168            'test_arg'  => '-V', 
     169            'test_output' => 'PMW version', 
     170        ), 
     171    ), 
     172); 
     173 
     174 
     175add_action ('scorerender_define_adm_msgs', 
     176    array( 'pmwRender', 'define_admin_messages' ) ); 
     177 
     178add_action ('scorerender_check_notation_progs', 
     179    array( 'pmwRender', 'is_notation_usable' ), 10, 2 ); 
     180 
     181add_filter ('scorerender_prog_and_file_loc', 
     182    array( 'pmwRender', 'program_setting_entry' ) ); 
     183 
     184add_filter ('scorerender_define_setting_type', 
     185    array( 'pmwRender', 'define_setting_type' ) ); 
     186 
     187add_filter ('scorerender_define_setting_value', 
     188    array( 'pmwRender', 'define_setting_value' ) ); 
    74189?> 
  • scorerender/trunk/readme.txt

    r209422 r209432  
    22Contributors: abelcheung 
    33Tags: music, music notation, music typesetting, score, abc, mup, lilypond, guido, pmw 
    4 Requires at least: 2.2 
    5 Tested up to: 2.8.3 
     4Requires at least: 2.6 
     5Tested up to: 2.9.2 
    66Stable tag: 0.3.3 
    77 
    8 Renders inline sheet music fragments in post, pages and comments. 
     8Renders inline sheet music fragments in excerpts, posts, pages and comments. 
    99 
    1010== Description == 
    1111 
    12 ScoreRender is a Wordpress plugin for rendering sheet music fragments into images.  It supports converting fragments in posts, pages and (optionally) comments.  Currently it supports 5 music notations: ABC, Guido, Lilypond, Mup and Philip's Music Writer. 
     12ScoreRender is a Wordpress plugin for rendering sheet music fragments into images.  It supports converting fragments in excerpts, posts, pages and (optionally) comments.  Currently it supports 5 music notations: ABC, Guido, Lilypond, Mup and Philip's Music Writer. 
    1313 
    14 ScoreRender started its life from Chris Lamb’s FigureRender plugin, which is a Wordpress plugin for rendering LaTeX and Lilypond music fragments into images. Its maintainership changed later. While continue enhancing FigureRender, all LaTeX related functionalities are submitted to [LatexRender](http://sixthform.info/steve/wordpress/), thus preserving this plugin for music rendering only and the rename. 
    15  
    16 For latest version, detailed usage instructions and demo cases, please visit [ScoreRender official site](http://scorerender.abelcheung.org/). Requires PHP5, ImageMagick and various programs to generate music score (except Guido notation). 
     14For latest version, detailed usage instructions and demo cases, please visit [ScoreRender official site](http://scorerender.abelcheung.org/). Requires PHP5, ImageMagick and various programs to generate music score. 
    1715 
    1816== Installation == 
    1917 
    2018###Prerequisite### 
    21 1. Starting from ScoreRender 0.2, PHP4 compatibility is dropped, and PHP5 is strictly needed. 
    22 2. Starting from ScoreRender 0.2, ImageMagick >= 6.3.6-2 is needed, due to usage of `-flatten` option. 
    23 3. Music rendering programs must also be installed on the same machine web server is running. For example, to support Lilypond fragments, Lilypond >= 2.8.1 must be installed in web server. Refer to [installation page](http://scorerender.abelcheung.org/installation/) for more detail. 
     19 
     201. **PHP 5.x** (PHP4 compatibility is dropped since 0.2; please visit [offical site](http://scorerender.abelcheung.org/) if ancient version using PHP4 is needed) 
     211. **ImageMagick >= 6.3.6-2** (due to usage of `-flatten` option). Newer version is better, since a bug about detecting PostScript transparency is fixed (updating pending in this area) 
     221. **Music rendering programs** must also be installed on the same machine web server is running. For example, to support Lilypond fragments, Lilypond >= 2.8.1 must be installed in web server. Most notations require explicit program to render, except GUIDO notation which fetches remote images instead. Refer to [installation page](http://scorerender.abelcheung.org/installation/) for more detail. 
    2423 
    2524###New install### 
     25 
    26261. Install any prerequisite programs as noted above. 
    27 2. Extract archive, and copy 'scorerender' folder to `wp-content/plugins/`, keeping the folder structure intact. 
    28 3. Login to WordPress and enable the plugin in admin interface. 
    29 4. Configure ScoreRender under the ScoreRender tab of the Options page. 
    30 5. In Option -> Writing, check if this option is turned on: 
     271. Extract archive, and copy 'scorerender' folder to `wp-content/plugins/`, keeping the folder structure intact. 
     281. Login to WordPress and enable the plugin in admin interface. 
     291. Configure ScoreRender under the ScoreRender tab of the Options page. 
     301. In Option -> Writing, check if this option is turned on: 
    3131 
    3232       "WordPress should correct invalidly nested XHTML automatically" 
     
    3737 
    3838###Upgrade### 
     39 
    39401. Deactivate the plugin in WordPress admin page. 
    40 2. Remove the whole plugin folder. 
    41 3. Upload new plugin and activate again. 
     411. Remove the whole plugin folder. 
     421. Upload new plugin and activate again. 
    4243 
    4344== Frequently Asked Questions == 
     
    4546= It just complains about some obscure error! = 
    4647 
    47 The error code indicates the kind of error in some degree. There are comments inside wp-scorerender.php indicating what kind of error it is. If you can't make any heads and tails out of PHP code, feel free to ask me [through email](http://me.abelcheung.org/aboutme/). 
     48The error code indicates the kind of error in some degree. There are comments inside wp-scorerender.php indicating what kind of error it is. If you can't make any heads and tails out of PHP code, feel free to [contact the author](http://me.abelcheung.org/aboutme/). 
    4849 
    4950= Why music score fragments are not rendered at all? = 
    5051 
    5152* Check if the beginning tag and ending tag of your music score fragment are correct. 
    52 * It will only be rendered if logged in user has 'unfiltered_html' capability, i.e. the user has 'Administrator' or 'Editor' role in WordPress. User can ask blog admin to boost their capabilities if needed. 
     53* It will only be rendered if logged in user has *unfiltered_html* capability, i.e. the user has *Administrator* or *Editor* role in WordPress. User can ask blog admin to boost their capabilities if needed. 
     54* Some programs required for certain notation may be not working or missing. 
    5355 
    5456= Is any ABC notation compatible program also supported? = 
    5557 
    56 Since 0.2, [abcm2ps](http://moinejf.free.fr/) will be the only one supported. This is a design decision. If you REALLY want to use other similar programs, you are on your own, though modifying the code to support others is not very hard. Take a look at `is_notation_usable()` method in class.abc.inc.php. 
     58Since 0.2, [abcm2ps](http://moinejf.free.fr/) will be the only one supported. This is a design decision. If you **REALLY** want to use other similar programs, you are on your own, though modifying the code to support others is not very hard. Take a look at `is_notation_usable()` method in `notation/abc.php`. 
    5759 
    5860= I want to remove cache for 1 image and re-render, but how can I determine which is which? = 
    5961 
    60 Right now you have to view HTML source to find out cache image file name. Management of cache is planned in future, but can't say when. 
     62Right now this is still impossible. Management of cache is planned in future, but can't say when. 
    6163 
    6264= Images using Guido notation seems blurred. = 
     
    6668= How to debug my fragment when posting? = 
    6769 
    68 Simply put, don't do that now if possible. There is no viable method for debugging a fragment yet. The best way is render it privately in your computer first, then post the content, rather than needlessly spending lots of time on trial and error. 
     70Simply answer: don't do that if possible. The best way is render it privately in your computer first, then post the content, rather than needlessly spending lots of time on trial and error. 
     71Long answer: There is no easy method for debugging a fragment yet. If there is no choice but perform trial and error, please search for this line in `wp-scorerender.php`: 
     72 
     73`   define (SR_DEBUG, FALSE);` 
     74 
     75Change `FALSE` to `TRUE`, then resubmit the content again. It has 2 purposes: 
     76 
     771. Erraneous fragments are not deleted from server temp folder, and you can try manually rendering the fragment using command line to see what's wrong. 
     781. Full command line for rendering is now shown on blog, so that you can check out if command line argument is wrong. 
    6979 
    7080= How can I install Philip's Music Writer? = 
    7181 
    72 Only by downloading source from its official website and compile the program yourself. The author failed to notice any binary package for Windows or Linux as of Feb 2009. 
     82Only by downloading source from its official website and compile the program yourself. The author failed to notice any binary package for Windows or Linux as of Feb 2010, except an outdated RPM package for Mandriva Linux. 
    7383 
    74 Compiling and using PMW on Windows may only be possible through code changes. 
     84Please refer to the documents inside PMW tarball on how to compile its source code. 
     85 
     86= I discovered a bug. How can I notify the author? = 
     87 
     88You can either [submit bug report to Googlecode](http://code.google.com/p/scorerender/issues/list) or [contact the author](http://me.abelcheung.org/aboutme/). 
    7589 
    7690== Screenshots == 
     
    7993 
    8094== License == 
    81 This plugin is released under GPL v2. 
    82 IE Alpha Fix is released under LGPL v2.1 or later. 
    83 Zero Clipboard is released under LGPL. 
     95 
     96* This plugin is licensed under GNU AGPL v3. 
     97* IE Alpha Fix is licensed under LGPL v2.1 or later. 
     98* Zero Clipboard is licensed under LGPL. 
     99* jQuery Color Picker is dual licensed under MIT and GPL. 
     100 
     101== Upgrade Notice == 
     102 
     103= 0.3.3 = 
     104 
     105* Safe mode for Lilypond notation is once again usable. 
     106* Users of more recent ImageMagick version will find that transparency for certain notations are fixed. 
     107* Also fix a bug prevented disabling of notation. 
     108 
     109= 0.3.2 = 
     110 
     111* Users of Lilypond 2.12.x should upgrade due to broken command line invocation. 
    84112 
    85113== Changelog == 
    86114 
    87 **Version 0.3.2** 
     115= 0.3.3 = 
    88116 
    89 * Fix invocation for LilyPond 2.12.x 
     117* Change license to AGPL v3. 
     118* 'Show source' setting is moved to 'Contents' admin section. 
     119* BUG FIX: Admin form html tags incorrectly nested. 
     120* BUG FIX: Notation was not deactivated even when program name is not filled. 
     121* BUG FIX: Restore safe mode for Lilypond, use precise version detection to determine command line argument. 
     122* BUG FIX: PostScript transparency shall be properly detected for PMW and Mup on recent ImageMagick versions. 
     123* BUG FIX: Prevents PMW from reading config file. 
     124* FEATURE: Add icon for admin form title (on recent WP versions). 
    90125 
    91 **Version 0.3.1** 
     126= 0.3.2 = 
    92127 
    93 * Incorporate certain fixes from trunk: 
    94 * Show image dimension in output 
    95 * Fix line break when showing score source code under Windows 
    96 * Better autodetection of program 
    97 * Bug fix in program availability checkinng 
     128* BUG FIX: Fix invocation for LilyPond 2.12.x 
    98129 
    99 **Version 0.3.0** 
     130= 0.3.1 = 
    100131 
    101 * Philip's Music Writer notation support. 
    102 * IE Alpha fix has been incorporated, which provides translucent PNG support for IE 5.5 / 6.x. Thus drop IE PNG transparency warning altogether.  
    103 * Zero Clipboard has been incorporated, which provides cross platform copy and paste via flash. Warning about non-IE browser during copy and paste is removed. 
    104 * Better support of installation on web hosting, where disabling certain PHP functions is common practise. 
     132* FEATURE: Show image dimension in output. 
     133* BUG FIX: Fix line break when showing score source code under Windows. 
     134* FEATURE: Better autodetection of program. 
     135* BUG FIX: program availability checking. 
     136 
     137= 0.3.0 = 
     138 
     139* FEATURE: Philip's Music Writer notation support. 
     140* FEATURE: IE Alpha fix has been incorporated, which provides translucent PNG support for IE 5.5 / 6.x. Thus drop IE PNG transparency warning altogether.  
     141* FEATURE: Zero Clipboard has been incorporated, which provides cross platform copy and paste via flash. Warning about non-IE browser during copy and paste is removed. 
     142* FEATURE: Better support of installation on web hosting, where disabling certain PHP functions is common practise. 
    105143* Rendering or not also depends on 'unfiltered_html' WordPress capability. 
    106144* Refactor functions and files, so admin page is only included when needed, and PHP class no longer access global variables. 
    107145 
    108 **Version 0.2.1** 
     146= 0.2.1 = 
    109147 
    110 * Fix turning on/off IE PNG transparency warning option. 
     148* BUG FIX: Toggling IE PNG transparency warning option was ineffective. 
    111149 
    112 **Version 0.2.0** 
     150= 0.2.0 = 
    113151 
    114152* Revamp admin page and simplify options. 
     
    118156* Mandates abcm2ps must be used for ABC notation support. 
    119157 
    120 **Version 0.1.3** 
     158= 0.1.3 = 
    121159 
    122160* Add WordPress nonce protection. 
    123161 
    124 **Version 0.1.2** 
     162= 0.1.2 = 
    125163 
    126164* Fix image rendering during ImageMagick conversion process. 
    127165 
    128 **Version 0.1.1** 
     166= 0.1.1 = 
    129167 
    130168* Fix transparency of images generated by Lilypond. 
    131 * Issue warning if 'correct invalidly nested XHTML automatically' option is checked, instead of turning the option off. 
     169* Issue warning if *correct invalidly nested XHTML automatically* option is checked, instead of turning the option off. 
    132170 
    133 **Version 0.1.0** 
     171= 0.1.0 = 
    134172 
    135173* Initial release. 
  • scorerender/trunk/scorerender-admin.php

    r114489 r209432  
    44 * ScoreRender documentation 
    55 * @package ScoreRender 
    6  * @version 0.2.50 
     6 * @version 0.3.50 
    77 * @author Abel Cheung <abelcheung at gmail dot com> 
    88 * @copyright Copyright (C) 2006 Chris Lamb <chris at chris-lamb dot co dot uk> 
    9  * @copyright Copyright (C) 2007, 08 Abel Cheung 
    10  * @license http://opensource.org/licenses/gpl-license.php GNU Public License 
    11  */ 
    12  
    13 /** 
    14  * Calculate number of fragments contained inside a blog post 
    15  * 
    16  * The returned numbers are mainly used for showing info in WordPress Dashboard 
     9 * @copyright Copyright (C) 2007, 2008, 2009, 2010 Abel Cheung 
     10 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU AGPL v3 
     11 */ 
     12 
     13 
     14/** 
     15 * This class is used for encapsulating various admin related functions 
     16 * 
     17 * @since 0.3.50 
     18 * @package ScoreRender 
     19 * @access private This class is not supposed to be used beyond ScoreRender 
     20*/ 
     21class ScoreRenderAdmin 
     22{ 
     23 
     24/** 
     25 * Returns number of cached images inside cache directory 
    1726 * 
    1827 * @since 0.2 
    19  * @uses $notations Content is compared to regex specified in $notations 
    20  * @param string $content the whole blog post content 
    21  * @return array $count Array containing number of matched fragments for each kind of notation 
    22  * 
    23  * @todo maybe store all info into separate table 
    24  */ 
    25 function scorerender_get_fragment_count ($content) 
    26 { 
    27     global $notations; 
    28  
    29     $count = array(); 
    30     foreach (array_values ($notations) as $notation) 
    31         $count[] = preg_match_all ($notation['regex'], $content, $matches); 
    32  
     28 * @uses scorerender_get_cache_location() For reading cached image folder and counting images 
     29 * @return integer number of images inside cache directory, or -1 if cache dir can't be read 
     30 * @access private 
     31 */ 
     32private function get_num_of_images () 
     33{ 
     34    if ( false === ( $handle = opendir (scorerender_get_cache_location()) ) ) return -1; 
     35 
     36    $count = 0; 
     37    while (false !== ($file = readdir ($handle))) 
     38        if (preg_match (REGEX_CACHE_IMAGE, $file)) $count++; 
     39 
     40    closedir ($handle); 
    3341    return $count; 
    3442} 
     
    3644 
    3745/** 
    38  * Returns number of cached images inside cache directory 
     46 * Remove all cached images in cache directory 
    3947 * 
    4048 * @since 0.2 
    41  * @return integer number of images inside cache directory, or -1 if cache dir can't be read 
    42  */ 
    43 function scorerender_get_num_of_images () 
    44 { 
    45     global $sr_options; 
    46  
    47     if (!is_dir ($sr_options['CACHE_DIR']) || !is_readable ($sr_options['CACHE_DIR'])) 
    48         return -1; 
    49  
    50     $count = 0; 
    51     if ($handle = opendir ($sr_options['CACHE_DIR'])) 
    52     { 
    53         while (false !== ($file = readdir ($handle))) 
    54         { 
    55             if (preg_match (REGEX_CACHE_IMAGE, $file)) 
    56                 $count++; 
    57         } 
    58         closedir ($handle); 
    59     } 
    60     return $count; 
    61 } 
    62  
    63  
    64 /** 
    65  * Display info in WordPress Dashboard 
    66  * 
    67  * @since 0.2 
    68  * @uses scorerender_get_fragment_count() 
    69  * @uses scorerender_get_num_of_images() 
    70  * @uses $notations Regex in $notations is used to compose SQL statement 
    71  * @access private 
    72  */ 
    73 function scorerender_activity_box () 
    74 { 
    75     global $wpdb, $notations; 
    76     $frag_count = 0; 
    77  
    78     $wpdb->hide_errors(); 
    79  
    80     // get posts first 
    81     $query_substr = array(); 
    82     foreach (array_values ($notations) as $notation) 
    83         $query_substr[] .= "post_content LIKE '%" . $notation['endtag'] . "%'"; 
    84     $query = "SELECT post_content FROM $wpdb->posts WHERE " . implode (" OR ", $query_substr); 
    85  
    86     $posts = $wpdb->get_col ($query); 
    87     $post_count = count ($posts); 
    88  
    89     if (0 < $post_count) 
    90         foreach ($posts as $post) 
    91             $frag_count += array_sum (scorerender_get_fragment_count ($post)); 
    92  
    93  
    94     // followed by comments 
    95     $query_substr = array(); 
    96     foreach (array_values ($notations) as $notation) 
    97         $query_substr[] .= "comment_content LIKE '%" . $notation['endtag'] . "%'"; 
    98     $query = sprintf ("SELECT comment_content FROM $wpdb->comments WHERE comment_approved = '1' AND (%s)", 
    99               implode (" OR ", $query_substr)); 
    100  
    101     $comments = $wpdb->get_col ($query); 
    102     $comment_count = count ($comments); 
    103  
    104     if (0 < $comment_count) 
    105         foreach ($comments as $comment) 
    106             $frag_count += array_sum (scorerender_get_fragment_count ($comment)); 
    107  
    108     $num_of_posts_str = sprintf (__ngettext ('%d post', '%d posts', $post_count, TEXTDOMAIN), $post_count); 
    109     $num_of_comments_str = sprintf (__ngettext ('%d comment', '%d comments', $comment_count, TEXTDOMAIN), $comment_count); 
    110  
    111  
    112     if ((0 === $post_count) && (0 === $comment_count)) 
    113         $first_sentence = __('This blog is currently empty.', TEXTDOMAIN); 
    114  
    115     elseif (0 === $frag_count) 
    116         $first_sentence = __('There is no music fragment in your blog.', TEXTDOMAIN); 
    117  
    118     elseif (0 === $comment_count) 
    119         $first_sentence = sprintf ( 
    120             __ngettext ('There is %d music fragment contained in %s.', 
    121                         'There are %d music fragments contained in %s.', 
    122                         $frag_count, TEXTDOMAIN), 
    123             $frag_count, $num_of_posts_str); 
    124  
    125     elseif (0 === $post_count) 
    126         $first_sentence = sprintf ( 
    127             __ngettext ('There is %d music fragment contained in %s.', 
    128                         'There are %d music fragments contained in %s.', 
    129                         $frag_count, TEXTDOMAIN), 
    130             $frag_count, $num_of_comments_str); 
    131  
    132     else 
    133         $first_sentence = sprintf ( 
    134             __ngettext ('There is %d music fragment contained in %s and %s.', 
    135                         'There are %d music fragments contained in %s and %s.', 
    136                         $frag_count, TEXTDOMAIN), 
    137             $frag_count, $num_of_posts_str, $num_of_comments_str); 
    138  
    139  
    140     $img_count = scorerender_get_num_of_images(); 
    141  
    142     if ( 0 > $img_count ) 
    143         $second_sentence = sprintf (__('<font color="red">The cache directory is either non-existant or not readable.</font> Please <a href="%s">change the setting</a> and make sure the directory exists.', TEXTDOMAIN), 'options-general.php?page=' . plugin_basename (__FILE__)); 
    144     else 
    145         $second_sentence = sprintf ( 
    146             __ngettext ('Currently %d image are rendered and cached.', 
    147                         'Currently %d images are rendered and cached.', 
    148                         $img_count, TEXTDOMAIN), 
    149                 $img_count); 
    150 ?> 
    151     <div> 
    152     <h3><?php _e('ScoreRender', TEXTDOMAIN) ?></h3> 
    153     <p><?php echo $first_sentence . '  ' . $second_sentence; ?></p> 
    154     </div> 
    155 <?php 
    156 } 
    157  
    158  
    159 /** 
    160  * Remove all cached images in cache directory 
    161  * 
    162  * @since 0.2 
    163  */ 
    164 function scorerender_remove_cache () 
    165 { 
    166     global $sr_options; 
    167  
    168     // extra guard, doesn't hurt 
    169     if (!is_dir      ($sr_options['CACHE_DIR']) || 
    170         !is_readable ($sr_options['CACHE_DIR']) || 
    171         !is_writable ($sr_options['CACHE_DIR'])) 
    172         return; 
    173  
    174     if ($handle = opendir ($sr_options['CACHE_DIR'])) 
    175     { 
    176         while (false !== ($file = readdir ($handle))) 
    177         { 
    178             // FIXME: how to decide if some image is generated by plugin? 
    179             if (preg_match (REGEX_CACHE_IMAGE, $file)) 
    180                 unlink ($sr_options['CACHE_DIR'] . DIRECTORY_SEPARATOR . $file); 
    181         } 
    182         closedir ($handle); 
    183     } 
     49 * @uses scorerender_get_cache_location() For searching cached image folder and deleting images 
     50 * @access private 
     51 */ 
     52private function remove_cache () 
     53{ 
     54    if ( false === ( $handle = opendir (scorerender_get_cache_location()) ) ) return; 
     55 
     56    while (false !== ($file = readdir ($handle))) 
     57    { 
     58        if (preg_match (REGEX_CACHE_IMAGE, $file)) 
     59            @unlink ($dir . DIRECTORY_SEPARATOR . $file); 
     60    } 
     61    closedir ($handle); 
     62 
    18463    return; 
    185 } 
    186  
    187  
    188 /** 
    189  * Check if cache folder and cache URL settings match or not. 
    190  * 
    191  * This is done by creating a temp file with random file name, and 
    192  * see if it is accessible via URL. 
    193  * 
    194  * Note that no error checking is done for path and URL, so make sure 
    195  * their validity are confirmed before using. 
    196  * 
    197  * @param string $path Cache full path 
    198  * @param string $url Cache URL 
    199  * @return boolean Whether both point to the same location. 
    200  */ 
    201 function scorerender_cache_location_match ($path, $url) 
    202 { 
    203     $retval = true; 
    204     /* 
    205      * Just a very crude check. Non-existance of URL before file creation 
    206      * is not verified; neither does non-existance of URL after file removal 
    207      */ 
    208     $tmpfile = tempnam ($path, (string) mt_rand()); 
    209  
    210     if (false === $tmpfile) 
    211         $retval = false; 
    212  
    213     else 
    214     { 
    215         if ( false === strpos ($tmpfile, $path) ) 
    216             $retval = false; 
    217         elseif ( false === ( $fh = @fopen ( 
    218                 trailingslashit($url).basename($tmpfile), 'r') ) ) 
    219             $retval = false; 
    220         else 
    221             fclose ($fh); 
    222  
    223         unlink ($tmpfile); 
    224     } 
    225     return $retval; 
    22664} 
    22765 
     
    23371 * error encountered in various options. In some cases supplied 
    23472 * config values will be discarded. 
    235  */ 
    236 function scorerender_update_options () 
    237 { 
    238     if ( function_exists ('current_user_can') && !current_user_can ('manage_options') ) 
     73 * 
     74 * @uses transform_paths() 
     75 * @uses ScoreRender::is_web_hosting() 
     76 * @uses ScoreRender::is_prog_usable() Check if ImageMagick is usable 
     77 * @uses scorerender_get_def_settings() 
     78 * @uses scorerender_get_cache_location() Also checks if cached image folder is writable 
     79 * @access private 
     80 */ 
     81private function update_options () 
     82{ 
     83    if ( !current_user_can ('manage_options') ) 
    23984        wp_die (__('Cheatin&#8217; uh?', TEXTDOMAIN)); 
    24085 
     
    24590    $errmsgs = array (); 
    24691 
    247     $messages = array 
     92    $sr_adm_msgs = array 
    24893    ( 
    249         'temp_dir_not_writable'    => array ('level' => MSG_WARNING, 'content' => __('Temporary directory is NOT writable! Will fall back to system default setting.')), 
    250         'cache_dir_undefined'      => array ('level' => MSG_FATAL  , 'content' => __('Cache directory is NOT defined! Image can not be placed inside appropriate directory. The plugin will stop working.', TEXTDOMAIN)), 
    251         'cache_dir_not_writable'   => array ('level' => MSG_FATAL  , 'content' => __('Cache directory is NOT writable! Image can not be placed inside appropriate directory. The plugin will stop working.', TEXTDOMAIN)), 
    252         'cache_url_undefined'      => array ('level' => MSG_FATAL  , 'content' => __('Cache URL is NOT defined! The plugin will stop working.', TEXTDOMAIN)), 
    253         'cache_dir_url_unmatch'    => array ('level' => MSG_WARNING, 'content' => __('Cache directory and URL probably do not correspond to the same location.', TEXTDOMAIN)), 
    254         'wrong_content_length'     => array ('level' => MSG_WARNING, 'content' => __('Content length is not a non-negative integer. Value discarded.', TEXTDOMAIN)), 
    255         'wrong_frag_per_comment'   => array ('level' => MSG_WARNING, 'content' => __('Fragment per comment is not a non-negative integer. Value discarded.', TEXTDOMAIN)), 
    256         'wrong_image_max_width'    => array ('level' => MSG_WARNING, 'content' => __('Image maximum width must be positive integer >= 72. Value discarded.', TEXTDOMAIN)), 
    257         'convert_bin_problem'      => array ('level' => MSG_FATAL  , 'content' => __('<tt>convert</tt> program is NOT defined or NOT executable! The plugin will stop working.', TEXTDOMAIN)), 
    258         'abcm2ps_bin_problem'      => array ('level' => MSG_WARNING, 'content' => sprintf (__('%s program does not look like a correct one. %s notation support will most likely stop working.', TEXTDOMAIN), '<tt>abcm2ps</tt>', 'ABC')), 
    259         'lilypond_bin_problem'     => array ('level' => MSG_WARNING, 'content' => sprintf (__('%s program does not look like a correct one. %s notation support will most likely stop working.', TEXTDOMAIN), '<tt>lilypond</tt>', 'LilyPond')), 
    260         'mup_bin_problem'          => array ('level' => MSG_WARNING, 'content' => sprintf (__('%s program does not look like a correct one. %s notation support will most likely stop working.', TEXTDOMAIN), '<tt>mup</tt>', 'Mup')), 
    261         'pmw_bin_problem'          => array ('level' => MSG_WARNING, 'content' => sprintf (__('%s program does not look like a correct one. %s notation support will most likely stop working.', TEXTDOMAIN), '<tt>pmw</tt>', 'Philip\'s Music Writer')), 
    262         'prog_check_disabled'      => array ('level' => MSG_WARNING, 'content' => sprintf (__('Some PHP functions are disabled due to security reasons. Program validation will not be done.', TEXTDOMAIN))), 
     94        'temp_dir_not_writable'  => array ( 
     95            'level'   => MSG_WARNING, 
     96            'content' => __('Temporary directory is NOT writable! Will fall back to system default setting.', TEXTDOMAIN)), 
     97        'cache_dir_not_writable' => array ( 
     98            'level'   => MSG_FATAL  , 
     99            'content' => sprintf (__('Cache directory is NOT writable! If default value is used, please go to <a href="%s">WordPress file upload setting</a> and check default upload directory; otherwise please make sure the cache directory you specified can be accessed by web server. The plugin will stop working.', TEXTDOMAIN)), admin_url('options-misc.php')), 
     100        'wrong_frag_per_comment' => array ( 
     101            'level'   => MSG_WARNING, 
     102            'content' => __('Fragment per comment is not a non-negative integer. Value discarded.', TEXTDOMAIN)), 
     103        'wrong_image_max_width'  => array ( 
     104            'level'   => MSG_WARNING, 
     105            'content' => __('Image maximum width must be positive integer >= 72. Value discarded.', TEXTDOMAIN)), 
     106        'convert_bin_problem'    => array ( 
     107            'level'   => MSG_FATAL  , 
     108            'content' => __('Failed to detect usable ImageMagick <tt>convert</tt> program! The plugin will stop working.', TEXTDOMAIN)), 
     109        'prog_check_disabled'    => array ( 
     110            'level'   => MSG_WARNING, 
     111            'content' => __('Some PHP functions are disabled due to security reasons. Program validation will not be done.', TEXTDOMAIN)), 
    263112    ); 
     113 
     114    // error message definition for each notation 
     115    do_action_ref_array ('scorerender_define_adm_msgs', array(&$sr_adm_msgs)); 
    264116 
    265117    /* 
    266118     * general options 
    267119     */ 
    268     if ( ! empty ($newopt['TEMP_DIR']) && 
     120    if ( !empty ($newopt['TEMP_DIR']) && 
    269121        !is_writable ($newopt['TEMP_DIR']) ) 
    270122    { 
     
    273125    } 
    274126 
    275     if ( empty ($newopt['CACHE_DIR']) ) 
    276         $errmsgs[] = 'cache_dir_undefined'; 
    277     elseif ( !is_writable ($newopt['CACHE_DIR']) ) 
    278         $errmsgs[] = 'cache_dir_not_writable'; 
    279  
    280     if ( empty ($newopt['CACHE_URL']) ) 
    281         $errmsgs[] = 'cache_url_undefined'; 
    282  
    283     if ( ! in_array ('cache_dir_undefined'   , $errmsgs) && 
    284          ! in_array ('cache_dir_not_writable', $errmsgs) && 
    285          ! in_array ('cache_url_undefined'   , $errmsgs) ) 
    286     { 
    287         if ( ! scorerender_cache_location_match ($newopt['CACHE_DIR'], $newopt['CACHE_URL']) ) 
    288             $errmsgs[] = 'cache_dir_url_unmatch'; 
     127    if ( !empty ($newopt['CACHE_DIR']) ) 
     128    { 
     129        if ( !is_writable ($newopt['CACHE_DIR']) ) 
     130            $errmsgs[] = 'cache_dir_not_writable'; 
     131    } 
     132    else 
     133    { 
     134        $newopt['CACHE_DIR'] = ''; 
     135        if ( !is_writable ( scorerender_get_cache_location() ) ) 
     136            $errmsgs[] = 'cache_dir_not_writable'; 
    289137    } 
    290138 
     
    301149            $newopt[$key] = isset ($newopt[$key]); 
    302150 
    303     if ( !ctype_digit ($newopt['CONTENT_MAX_LENGTH']) ) 
    304     { 
    305         $errmsgs[] = 'wrong_content_length'; 
    306         unset ($newopt['CONTENT_MAX_LENGTH']); 
    307     } 
    308  
    309151    if ( isset ($newopt['FRAGMENT_PER_COMMENT']) && 
    310152        !ctype_digit ($newopt['FRAGMENT_PER_COMMENT']) ) 
     
    320162    } 
    321163 
    322     // FIXME: Anyway to do pluggable checking without access these methods directly? 
    323     if ( ! empty ($newopt['LILYPOND_BIN']) && 
    324             ! lilypondRender::is_notation_usable ('prog=' . $newopt['LILYPOND_BIN']) ) 
    325         $errmsgs[] = 'lilypond_bin_problem'; 
    326  
    327     if ( ! empty ($newopt['MUP_BIN']) && 
    328             ! mupRender::is_notation_usable ('prog=' . $newopt['MUP_BIN']) ) 
    329         $errmsgs[] = 'mup_bin_problem'; 
    330  
    331     if ( ! empty ($newopt['ABCM2PS_BIN']) && 
    332             ! abcRender::is_notation_usable ('prog=' . $newopt['ABCM2PS_BIN']) ) 
    333         $errmsgs[] = 'abcm2ps_bin_problem'; 
    334  
    335     if ( ! empty ($newopt['PMW_BIN']) && 
    336             ! pmwRender::is_notation_usable ('prog=' . $newopt['PMW_BIN']) ) 
    337         $errmsgs[] = 'pmw_bin_problem'; 
     164    // program checking for each notation 
     165    do_action_ref_array ('scorerender_check_notation_progs', array(&$errmsgs, &$newopt)); 
    338166 
    339167    $sr_options = array_merge ($sr_options, $newopt); 
     
    346174        foreach (array_values ($errmsgs) as $m) 
    347175        { 
    348             if ($messages[$m]['level'] == MSG_WARNING) 
    349                 echo '<div id="scorerender-error-' . $messages[$m] . '" class="updated fade-800000"><p><strong>' . sprintf (__('WARNING: %s', TEXTDOMAIN), $messages[$m]['content']) . "</strong></p></div>\n"; 
    350             elseif ($messages[$m]['level'] == MSG_FATAL) 
    351                 echo '<div id="scorerender-error-' . $messages[$m] . '" class="updated" style="background-color: #800000; color: white;"><p><strong>' . sprintf (__('ERROR: %s', TEXTDOMAIN), $messages[$m]['content']) . "</strong></p></div>\n"; 
     176            if ($sr_adm_msgs[$m]['level'] == MSG_WARNING) 
     177            { 
     178                $class = 'scorerender-warning'; 
     179                $mesg = __('WARNING: %s', TEXTDOMAIN); 
     180            } 
     181            elseif ($sr_adm_msgs[$m]['level'] == MSG_FATAL) 
     182            { 
     183                $class = 'scorerender-error'; 
     184                $mesg = __('ERROR: %s', TEXTDOMAIN); 
     185            } 
     186 
     187            printf ("<div id='%s' class='error %s'><p><strong>%s</strong></p></div>\n", 
     188                    'sr-err-' . $sr_adm_msgs[$m], 
     189                    $class, 
     190                    sprintf ($mesg, $sr_adm_msgs[$m]['content']) 
     191                   ); 
    352192        } 
    353193    } 
     
    359199 
    360200/** 
     201 * WP hook added to admin page header 
     202 * 
     203 * @since 0.3 
     204 */ 
     205public function admin_head() 
     206{ 
     207?> 
     208<style type="text/css"> 
     209    .sr-help-icon {vertical-align:middle;border:none;} 
     210    #note_color_picker {width:36px; height:36px;} 
     211    #note_color_picker div { 
     212        position:relative; 
     213        top:4px; left:4px; 
     214        width:28px; height:28px; 
     215        background:url(<?php echo plugins_url ('scorerender/images/select2.png'); ?>) center; 
     216    } 
     217</style> 
     218<link rel="stylesheet" media="screen" type="text/css" href="<?php echo plugins_url ('scorerender/misc/colorpicker.css'); ?>" /> 
     219<?php 
     220} 
     221 
     222 
     223/** 
     224 * WP hook added to admin page footer 
     225 * 
     226 * Mainly include javascripts involved in admin form 
     227 * 
     228 * @since 0.3.50 
     229 */ 
     230public function admin_footer() 
     231{ 
     232    global $sr_options; 
     233?> 
     234<script type="text/javascript"> 
     235//<![CDATA[ 
     236jQuery(document).ready(function($){ 
     237    $("#comment_enabled").click(function() { 
     238        if ( $(this).is(":checked") ) 
     239        { 
     240            $("#fragment_per_comment").removeAttr("disabled"); 
     241            $("#fragment_per_comment").removeClass("disabled"); 
     242        } 
     243        else 
     244        { 
     245            $("#fragment_per_comment").attr('disabled', true); 
     246            $("#fragment_per_comment").addClass("disabled"); 
     247        } 
     248    }); 
     249    $('#note_color_picker').ColorPicker({ 
     250        eventName: 'mouseover', 
     251        color: '<?php echo $sr_options['NOTE_COLOR']; ?>', 
     252        onShow: function (foo) { 
     253            $(foo).fadeIn (500); 
     254            return false; 
     255        }, 
     256        onHide: function (foo) { 
     257            $(foo).fadeOut (500); 
     258            return false; 
     259        }, 
     260        onChange: function (hsb, hex, rgb) { 
     261            $('#note_color_picker div').css('background-color', '#' + hex); 
     262            $('#note_color').val('#' + hex); 
     263        } 
     264    }); 
     265}); 
     266//]]> 
     267</script> 
     268<script type="text/javascript" src="<?php echo plugins_url ('scorerender/misc/colorpicker.js'); ?>"></script> 
     269<?php 
     270} 
     271 
     272/** 
    361273 * Section of admin page about path options 
    362274 * 
     
    364276 * @access private 
    365277 */ 
    366 function scorerender_admin_section_path () 
     278private function admin_section_path () 
    367279{ 
    368280    global $sr_options; 
    369281?> 
    370     <fieldset class="options"> 
    371         <h3><?php _e('Path options', TEXTDOMAIN) ?></h3> 
    372  
    373         <table width="100%" cellspacing="2" cellpadding="5" class="optiontable editform form-table"> 
    374         <tr valign="top"> 
    375             <th scope="row"><?php _e('Temporary directory:', TEXTDOMAIN) ?></th> 
    376             <td> 
    377                 <input name="ScoreRender[TEMP_DIR]" class="code" type="text" id="temp_dir" value="<?php echo $sr_options['TEMP_DIR']; ?>" size="60" /><br /> 
    378                 <?php _e('Must be writable and ideally <strong>NOT</strong> accessible from web. System default will be used if left blank.', TEXTDOMAIN) ?> 
    379             </td> 
    380         </tr> 
    381         <tr valign="top"> 
    382             <th scope="row"><?php _e('Image cache directory:', TEXTDOMAIN) ?></th> 
    383             <td> 
    384                 <input name="ScoreRender[CACHE_DIR]" class="code" type="text" id="cache_dir" value="<?php echo $sr_options['CACHE_DIR']; ?>" size="60" /><br /> 
    385                 <?php _e('Must be writable and accessible from web.', TEXTDOMAIN) ?> 
    386             </td> 
    387         </tr> 
    388         <tr valign="top"> 
    389             <th scope="row"><?php _e('Image cache URL:', TEXTDOMAIN) ?></th> 
    390             <td> 
    391                 <input name="ScoreRender[CACHE_URL]" class="code" type="text" id="cache_url" value="<?php echo $sr_options['CACHE_URL']; ?>" size="60" /><br /> 
    392                 <?php _e('Must correspond to the image cache directory above.', TEXTDOMAIN) ?> 
    393             </td> 
    394         </tr> 
    395         </table> 
    396     </fieldset> 
     282 
     283<h3><?php _e('Path options', TEXTDOMAIN) ?></h3> 
     284<table class="form-table"> 
     285 
     286<tr valign="top"> 
     287<th scope="row"><label for="temp_dir"><?php _e('Temporary directory:', TEXTDOMAIN) ?></label></th> 
     288<td> 
     289<input name="ScoreRender[TEMP_DIR]" type="text" id="temp_dir" value="<?php echo $sr_options['TEMP_DIR']; ?>" class="regular-text code" /> 
     290<div class="setting-description"><?php _e('Must be writable and ideally <strong>NOT</strong> accessible from web. System default will be used if left blank.', TEXTDOMAIN) ?></div> 
     291</td> 
     292</tr> 
     293 
     294<tr valign="top"> 
     295<th scope="row"><label for="cache_dir"><?php _e('Image cache directory:', TEXTDOMAIN) ?></label></th> 
     296<td> 
     297<input name="ScoreRender[CACHE_DIR]" type="text" id="cache_dir" value="<?php echo $sr_options['CACHE_DIR']; ?>" class="regular-text code" /> 
     298<div class="setting-description"><?php _e('Must be writable and accessible from web. WordPress default upload directory is used if left blank.', TEXTDOMAIN) ?></div> 
     299</td> 
     300</tr> 
     301 
     302</table> 
    397303<?php 
    398304} 
     
    405311 * @access private 
    406312 */ 
    407 function scorerender_admin_section_prog () 
     313private function admin_section_prog () 
    408314{ 
    409315    global $sr_options; 
    410316?> 
    411     <fieldset class="options"> 
    412         <h3><?php _e('Program and file locations', TEXTDOMAIN) ?></h3> 
    413         <table width="100%" cellspacing="2" cellpadding="5" class="optiontable editform form-table"> 
    414         <caption><?php _e('ImageMagick 6.x <code>convert</code> must be present and working. For each kind of notation, leaving corresponding program location empty means disabling that notation support automatically, except GUIDO which does not use any program.', TEXTDOMAIN); ?></caption> 
    415         <tr valign="top"> 
    416             <th scope="row"><?php printf (__('Location of %s binary:', TEXTDOMAIN), '<code>convert</code>') ?></th> 
    417             <td> 
    418                 <input name="ScoreRender[CONVERT_BIN]" class="code" type="text" id="convert_bin" value="<?php echo $sr_options['CONVERT_BIN']; ?>" size="50" /> 
    419             </td> 
    420         </tr> 
    421         <tr valign="top"> 
    422             <th scope="row"><?php printf (__('Location of %s binary:', TEXTDOMAIN), '<code>lilypond</code>'); ?></th> 
    423             <td> 
    424                 <input name="ScoreRender[LILYPOND_BIN]" class="code" type="text" id="lilypond_bin" value="<?php echo $sr_options['LILYPOND_BIN']; ?>" size="50" /> 
    425             </td> 
    426         </tr> 
    427         <tr valign="top"> 
    428             <th scope="row"><?php printf (__('Location of %s binary:', TEXTDOMAIN), '<code>mup</code>'); ?></th> 
    429             <td> 
    430                 <input name="ScoreRender[MUP_BIN]" class="code" type="text" id="mup_bin" value="<?php echo $sr_options['MUP_BIN']; ?>" size="50" /> 
    431             </td> 
    432         </tr> 
    433         <tr valign="top"> 
    434             <th scope="row"><?php printf (__('Location of %s magic file:', TEXTDOMAIN), '<code>mup</code>'); ?></th> 
    435             <td> 
    436                 <input name="ScoreRender[MUP_MAGIC_FILE]" class="code" type="text" id="mup_magic_file" value="<?php echo $sr_options['MUP_MAGIC_FILE']; ?>" size="50" /> 
    437                 <br /> 
    438                 <?php printf (__('Leave it empty if you have not <a href="%s">registered</a> Mup. This file must be readable by the user account running web server.', TEXTDOMAIN), 'http://www.arkkra.com/doc/faq.html#payment'); ?> 
    439             </td> 
    440         </tr> 
    441         <tr valign="top"> 
    442             <th scope="row"><?php printf (__('Location of %s binary:', TEXTDOMAIN), '<code>abcm2ps</code>'); ?></th> 
    443             <td> 
    444                 <input name="ScoreRender[ABCM2PS_BIN]" class="code" type="text" id="abcm2ps_bin" value="<?php echo $sr_options['ABCM2PS_BIN']; ?>" size="50" /> 
    445             </td> 
    446         </tr> 
    447         <tr valign="top"> 
    448             <th scope="row"><?php printf (__('Location of %s binary:', TEXTDOMAIN), '<code>pmw</code>'); ?></th> 
    449             <td> 
    450                 <input name="ScoreRender[PMW_BIN]" class="code" type="text" id="pmw_bin" value="<?php echo $sr_options['PMW_BIN']; ?>" size="50" /> 
    451             </td> 
    452         </tr> 
    453         </table> 
    454     </fieldset> 
     317 
     318<h3><?php _e('Program and file locations', TEXTDOMAIN) ?></h3> 
     319<table class="form-table"> 
     320 
     321<tr valign="top"> 
     322<th scope="row"><label for="convert_bin"><?php printf (__('Location of %s binary:', TEXTDOMAIN), '<code>convert</code>') ?></label></th> 
     323<td><input name="ScoreRender[CONVERT_BIN]" type="text" id="convert_bin" value="<?php echo $sr_options['CONVERT_BIN']; ?>" class="regular-text code" /></td> 
     324</tr> 
     325 
     326<?php 
     327    $output = apply_filters ('scorerender_prog_and_file_loc', $output); 
     328    echo $output; 
     329?> 
     330 
     331</table> 
    455332<?php 
    456333} 
     
    462339 * @access private 
    463340 */ 
    464 function scorerender_admin_section_image () 
     341private function admin_section_image () 
    465342{ 
    466343    global $sr_options; 
    467344?> 
    468     <fieldset class="options"> 
    469         <h3><?php _e('Image options', TEXTDOMAIN) ?></h3> 
    470         <table width="100%" cellspacing="2" cellpadding="5" class="optiontable editform form-table"> 
    471         <tr valign="top"> 
    472             <th scope="row"><?php _e('Max image width (pixel):', TEXTDOMAIN) ?></th> 
    473             <td> 
    474                 <input type="text" name="ScoreRender[IMAGE_MAX_WIDTH]" id="image_max_width" value="<?php echo $sr_options['IMAGE_MAX_WIDTH']; ?>" size="6" /> 
    475                 <label for="image_max_width"><?php _e('(Default is 360)', TEXTDOMAIN) ?></label><br /><?php _e('Note that this value is just an approximation, please allow for &#x00B1;10% difference. Some programs like lilypond would not use the full image width if passage is not long enough.', TEXTDOMAIN) ?></label> 
    476             </td> 
    477         </tr> 
    478         <tr valign="top"> 
    479             <th score="row"><?php _e('Clickable image:', TEXTDOMAIN) ?></th> 
    480             <td> 
    481                 <input type="checkbox" name="ScoreRender[SHOW_SOURCE]" id="show_input" value="1" <?php checked('1', $sr_options['SHOW_SOURCE']); ?> /> 
    482                 <label for="show_input"><?php _e('Show music source in new browser window/tab when image is clicked', TEXTDOMAIN); ?></label> 
    483             </td> 
    484         </tr> 
    485         <tr valign="top"> 
    486             <th score="row"><?php _e('Image post-processing', TEXTDOMAIN) ?></th> 
    487             <td> 
    488                 <p><input type="checkbox" name="ScoreRender[INVERT_IMAGE]" id="invert_image" value="1" <?php checked('1', $sr_options['INVERT_IMAGE']); ?> /> 
    489                 <label for="invert_image"><?php _e('White colored notes (default is black)', TEXTDOMAIN); ?></label></p> 
    490                 <p><input type="checkbox" name="ScoreRender[TRANSPARENT_IMAGE]" id="transparent_image" value="1" <?php checked('1', $sr_options['TRANSPARENT_IMAGE']); ?> onclick="var box = document.getElementById('use_ie6_png_alpha_fix'); box.disabled = !box.disabled; return true;" /> 
    491                 <label for="transparent_image"><?php _e('Use transparent background', TEXTDOMAIN); ?></label></p> 
    492                 <p style="padding-left: 30px;"><input type="checkbox" name="ScoreRender[USE_IE6_PNG_ALPHA_FIX]" id="use_ie6_png_alpha_fix" value="1" <?php checked('1', $sr_options['USE_IE6_PNG_ALPHA_FIX']); if (1 != $sr_options['TRANSPARENT_IMAGE']) { echo ' disabled="disabled"'; } ?> /> 
    493                 <label for="use_ie6_png_alpha_fix"><?php _e('Enable fake translucent image in IE6', TEXTDOMAIN) ?></label><br /><small><?php printf ('Turning on this option enables <a href="%s">emulation of translucency in PNG images</a> in IE 5.5/6, which is not supported by IE below version 7. This option only affects images rendered by ScoreRender. <strong>Make sure you have NOT installed any plugin with the same functionality before turning on this option, which may conflict with each other.</strong>', 'http://www.twinhelix.com/css/iepngfix/' ); ?></small></p> 
    494             </td> 
    495         </tr> 
    496         </table> 
    497     </fieldset> 
     345<h3><?php _e('Image options', TEXTDOMAIN) ?></h3> 
     346<table class="form-table"> 
     347 
     348<tr valign="top"> 
     349<th scope="row"><?php _e('Max image width:', TEXTDOMAIN) ?></th> 
     350<td><?php printf(__('%s pixels', TEXTDOMAIN), '<input type="text" name="ScoreRender[IMAGE_MAX_WIDTH]" id="image_max_width" value="' . $sr_options['IMAGE_MAX_WIDTH'] . '" class="small-text" />'); ?> 
     351<div class="setting-description"><?php _e('Note that this value is just an approximation, please allow for &#x00B1;10% difference. Some programs like lilypond would not use the full image width if passage is not long enough.', TEXTDOMAIN) ?></div> 
     352</td> 
     353</tr> 
     354 
     355<tr valign="top"> 
     356<th scope="row"><?php _e('Note color:', TEXTDOMAIN) ?></th> 
     357<td> 
     358<div id="note_color_picker"><div style="background-color: <?php echo $sr_options['NOTE_COLOR'] ?>"></div></div> 
     359<div class="setting-description"><?php _e('Move mouse pointer to the colored square above to pick desired color.', TEXTDOMAIN) ?></div> 
     360<input type="hidden" id="note_color" name="ScoreRender[NOTE_COLOR]" value="<?php echo $sr_options['NOTE_COLOR'] ?>" /> 
     361</td> 
     362</tr> 
     363 
     364<tr valign="top"> 
     365<th scope="row"><?php _e('IE Hack:', TEXTDOMAIN) ?></th> 
     366<td> 
     367<label for="use_ie6_png_alpha_fix"><input type="checkbox" name="ScoreRender[USE_IE6_PNG_ALPHA_FIX]" id="use_ie6_png_alpha_fix" value="1" <?php checked('1', $sr_options['USE_IE6_PNG_ALPHA_FIX']); ?> /> 
     368<?php _e('Enable fake translucent image in IE6', TEXTDOMAIN) ?></label> 
     369<div class="setting-description"><?php printf ('Turning on this option enables <a href="%s">emulation of translucency in PNG images</a> in IE 5.5/6, which is not supported by IE below version 7. This option only affects images rendered by ScoreRender. <strong>Make sure you have NOT installed any plugin with the same functionality before turning on this option, which may conflict with each other.</strong>', 'http://www.twinhelix.com/css/iepngfix/' ); ?></div> 
     370</td> 
     371</tr> 
     372 
     373</table> 
    498374<?php 
    499375} 
     
    507383 * @access private 
    508384 */ 
    509 function scorerender_admin_section_content () 
     385private function admin_section_content () 
    510386{ 
    511387    global $sr_options; 
    512388?> 
    513     <fieldset class="options"> 
    514         <h3><?php _e('Content options', TEXTDOMAIN) ?></h3> 
    515  
    516         <table width="100%" cellspacing="2" cellpadding="5" class="optiontable editform form-table"> 
    517         <tr valign="top"> 
    518             <th scope="row"><?php _e('Maximum length per fragment:', TEXTDOMAIN) ?></th> 
    519             <td> 
    520                 <input type="text" name="ScoreRender[CONTENT_MAX_LENGTH]" id="content_max_length" value="<?php echo $sr_options['CONTENT_MAX_LENGTH']; ?>" size="6" /> 
    521                 <label for="content_max_length"><?php _e('(0 means unlimited)', TEXTDOMAIN) ?></label> 
    522             </td> 
    523         </tr> 
    524         <tr valign="top"> 
    525             <th scope="row"><?php _e('When rendering failed:', TEXTDOMAIN); ?></th> 
    526             <td> 
    527                 <input type="radio" name="ScoreRender[ERROR_HANDLING]" id="on_err_show_message" value="1" <?php checked(ON_ERR_SHOW_MESSAGE, $sr_options['ERROR_HANDLING']); ?> /> 
    528                 <label for="on_err_show_message"><?php _e('Show error message', TEXTDOMAIN) ?></label><br /> 
    529                 <input type="radio" name="ScoreRender[ERROR_HANDLING]" id="on_err_show_fragment" value="2" <?php checked(ON_ERR_SHOW_FRAGMENT, $sr_options['ERROR_HANDLING']); ?> /> 
    530                 <label for="on_err_show_fragment"><?php _e('Show original, unmodified music fragment', TEXTDOMAIN) ?></label><br /> 
    531                 <input type="radio" name="ScoreRender[ERROR_HANDLING]" id="on_err_show_nothing" value="3" <?php checked(ON_ERR_SHOW_NOTHING, $sr_options['ERROR_HANDLING']); ?> /> 
    532                 <label for="on_err_show_nothing"><?php _e('Show nothing', TEXTDOMAIN) ?></label> 
    533             </td> 
    534         </tr> 
    535         <tr valign="top"> 
    536             <th scope="row"><?php _e('Comment rendering:', TEXTDOMAIN) ?></th> 
    537             <td> 
    538                 <input type="checkbox" name="ScoreRender[COMMENT_ENABLED]" id="comment_enabled" value="1" <?php checked('1', $sr_options['COMMENT_ENABLED']); ?> onclick="var box = document.getElementById('fragment_per_comment'); box.disabled = !box.disabled; return true;" /> 
    539                 <label for="comment_enabled"><?php printf ('%s %s', __('Enable rendering for comments', TEXTDOMAIN), '<span style="font-weight: bold; color: red;">' . __('(Only turn on if commenters are trusted)', TEXTDOMAIN) . '</span>'); ?></label> 
    540             </td> 
    541         </tr> 
    542         <tr valign="top"> 
    543             <th scope="row"><?php _e('Maximum number of fragment per comment:', TEXTDOMAIN) ?></th> 
    544             <td> 
    545                 <input type="text" name="ScoreRender[FRAGMENT_PER_COMMENT]" id="fragment_per_comment" value="<?php echo $sr_options['FRAGMENT_PER_COMMENT']; ?>" size="6" <?php if (1 != $sr_options['COMMENT_ENABLED']) { echo ' disabled="disabled"'; } ?> /> 
    546                 <label for="fragment_per_comment"><?php _e('(0 means unlimited)', TEXTDOMAIN) ?><br /><?php printf (__('If you don&#8217;t want comment rendering, turn off &#8216;<i>%s</i>&#8217; checkbox above instead. This option does not affect posts and pages.', TEXTDOMAIN), __('Enable rendering for comments', TEXTDOMAIN)); ?></label> 
    547             </td> 
    548         </tr> 
    549         </table> 
    550     </fieldset> 
     389<h3><?php _e('Content options', TEXTDOMAIN) ?></h3> 
     390<table class="form-table"> 
     391 
     392<tr valign="top"> 
     393<th scope="row"><?php _e('Show source:', TEXTDOMAIN) ?></th> 
     394<td><label for="show_input"><input type="checkbox" name="ScoreRender[SHOW_SOURCE]" id="show_input" value="1" <?php checked('1', $sr_options['SHOW_SOURCE']); ?> /> 
     395<?php _e('Show music source in new browser window/tab when image is clicked', TEXTDOMAIN); ?></label> 
     396</td> 
     397</tr> 
     398 
     399<tr valign="top"> 
     400<th scope="row"><?php _e('When rendering failed:', TEXTDOMAIN); ?></th> 
     401<td> 
     402<fieldset><legend class="hidden screen-reader-text"><?php _e('When rendering failed:', TEXTDOMAIN); ?></legend> 
     403<label for="on_err_show_message"><input type="radio" name="ScoreRender[ERROR_HANDLING]" id="on_err_show_message" value="1" <?php checked(ON_ERR_SHOW_MESSAGE, $sr_options['ERROR_HANDLING']); ?> /> 
     404<?php _e('Show error message', TEXTDOMAIN) ?></label><br /> 
     405<label for="on_err_show_fragment"><input type="radio" name="ScoreRender[ERROR_HANDLING]" id="on_err_show_fragment" value="2" <?php checked(ON_ERR_SHOW_FRAGMENT, $sr_options['ERROR_HANDLING']); ?> /> 
     406<?php _e('Show original, unmodified music fragment', TEXTDOMAIN) ?></label><br /> 
     407<label for="on_err_show_nothing"><input type="radio" name="ScoreRender[ERROR_HANDLING]" id="on_err_show_nothing" value="3" <?php checked(ON_ERR_SHOW_NOTHING, $sr_options['ERROR_HANDLING']); ?> /> 
     408<?php _e('Show nothing', TEXTDOMAIN) ?></label> 
     409</fieldset> 
     410</td> 
     411</tr> 
     412 
     413<tr valign="top"> 
     414<th scope="row"><?php _e('Comment rendering:', TEXTDOMAIN) ?></th> 
     415<td> 
     416<label for="comment_enabled"><input type="checkbox" name="ScoreRender[COMMENT_ENABLED]" id="comment_enabled" value="1" <?php checked('1', $sr_options['COMMENT_ENABLED']); ?> /> 
     417<?php _e('Enable rendering for comments', TEXTDOMAIN) ?></label> 
     418<div class="setting-description" style="color: red;"><?php _e('Only turn on if commenters are trusted', TEXTDOMAIN) ?></div> 
     419</td> 
     420</tr> 
     421 
     422<tr valign="top"> 
     423<th scope="row"><?php _e('Maximum number of fragment per comment:', TEXTDOMAIN) ?></th> 
     424<td> 
     425<label for="fragment_per_comment"><input type="text" name="ScoreRender[FRAGMENT_PER_COMMENT]" id="fragment_per_comment" value="<?php echo $sr_options['FRAGMENT_PER_COMMENT']; ?>" <?php echo (1 != $sr_options['COMMENT_ENABLED']) ? 'class="small-text disabled" disabled="disabled"' : 'class="small-text"'; ?> /></label> 
     426<span class="setting-description"><?php _e('(0 means unlimited)', TEXTDOMAIN) ?><br /><?php printf (__('If you don&#8217;t want comment rendering, turn off &#8216;<i>%s</i>&#8217; checkbox above instead. This option does not affect posts and pages.', TEXTDOMAIN), __('Enable rendering for comments', TEXTDOMAIN)); ?></span> 
     427</td> 
     428</tr> 
     429 
     430</table> 
    551431<?php 
    552432} 
     
    558438 * 
    559439 * @since 0.2 
    560  * @access private 
    561  */ 
    562 function scorerender_admin_section_caching () 
    563 { 
    564     global $sr_options; 
    565 ?> 
    566     <fieldset class="options"> 
    567         <h3><?php _e('Caching', TEXTDOMAIN) ?></h3> 
    568 <?php 
    569     $img_count = scorerender_get_num_of_images(); 
     440 * @uses ScoreRenderAdmin::get_num_of_images() Get and show cached image count 
     441 * @uses scorerender_get_cache_location() Check if the cached image folder is read-writable 
     442 * @access private 
     443 */ 
     444private function admin_section_caching () 
     445{ 
     446?> 
     447    <h3><?php _e('Caching', TEXTDOMAIN) ?></h3> 
     448<?php 
     449    $img_count = $this->get_num_of_images(); 
    570450 
    571451    if ( 0 > $img_count ) 
    572     { 
    573452        echo "<font color='red'>" . __('Cache directory is not readable, thus no image count is shown.', TEXTDOMAIN) . "<br />"; 
    574         echo __('Please change &#8216;Image cache directory&#8217; setting, or fix its permission.', TEXTDOMAIN) . "</font>\n"; 
    575     } 
    576453    else 
    577     { 
    578454        printf (__ngettext("Cache directory contains %d image.\n", 
    579                        "Cache directory contains %d images.\n", 
    580                        $img_count, TEXTDOMAIN), $img_count); 
    581     } 
    582  
    583 ?> 
    584 <?php if ( is_writable ($sr_options['CACHE_DIR']) ) : ?> 
    585         <input type="submit" name="clear_cache" value="<?php _e('Clear Cache &raquo;', TEXTDOMAIN) ?>" /> 
     455                   "Cache directory contains %d images.\n", 
     456                   $img_count, TEXTDOMAIN), $img_count); 
     457 
     458    $dir = scorerender_get_cache_location(); 
     459    if ( is_writable ($dir) && is_readable ($dir) ) : 
     460?> 
     461    <input type="submit" name="clear_cache" class="button-secondary" value="<?php _e('Clear Cache &raquo;', TEXTDOMAIN) ?>" /> 
    586462<?php else : ?> 
    587         <input type="submit" name="clear_cache" disabled="disabled" value="<?php _e('Clear Cache &raquo;', TEXTDOMAIN) ?>" /> 
    588         <br /><font color="red"><?php _e('Cache can&#8217;t be cleared because directory is not writable.', TEXTDOMAIN) ?><br /><?php _e('Please change &#8216;Image cache directory&#8217; setting, or fix its permission.', TEXTDOMAIN) ?></font> 
    589 <?php endif; ?> 
    590     </fieldset> 
    591 <?php 
     463    <input type="submit" name="clear_cache" class="button-secondary" disabled="disabled" value="<?php _e('Clear Cache &raquo;', TEXTDOMAIN) ?>" /> 
     464    <br /><font color="red"><?php echo $dir; _e('Cache can&#8217;t be cleared because folder permission is incorrect. It must be both readable and writable by web server.', TEXTDOMAIN) ?></font> 
     465<?php endif; 
    592466} 
    593467 
     
    597471 * 
    598472 * It also checks if form button is pressed, and may call 
    599  * {@link scorerender_remove_cache() scorerender_remove_cache()} or 
    600  * {@link scorerender_update_options() scorerender_update_options()} correspondingly. 
    601  * 
    602  * @uses scorerender_remove_cache() Activated when 'Remove Cache' button is clicked 
    603  * @uses scorerender_update_options() Activate when 'Update Options' button is clicked 
    604  * @uses scorerender_admin_section_path() Admin page -- path options 
    605  * @uses scorerender_admin_section_prog() Admin page -- program and file locations 
    606  * @uses scorerender_admin_section_image() Admin page -- image options 
    607  * @uses scorerender_admin_section_content() Admin page -- content options 
    608  * @uses scorerender_admin_section_caching() Admin page -- caching administration 
    609  * 
    610  * @access private 
    611  */ 
    612 function scorerender_admin_options () 
     473 * {@link ScoreRenderAdmin::remove_cache()} or 
     474 * {@link ScoreRenderAdmin::update_options()} correspondingly. 
     475 * 
     476 * @uses ScoreRenderAdmin::remove_cache() Activated when 'Remove Cache' button is clicked 
     477 * @uses ScoreRenderAdmin::update_options() Activate when 'Update Options' button is clicked 
     478 * @uses ScoreRenderAdmin::admin_section_path() Admin page -- path options 
     479 * @uses ScoreRenderAdmin::admin_section_prog() Admin page -- program and file locations 
     480 * @uses ScoreRenderAdmin::admin_section_image() Admin page -- image options 
     481 * @uses ScoreRenderAdmin::admin_section_content() Admin page -- content options 
     482 * @uses ScoreRenderAdmin::admin_section_caching() Admin page -- caching administration 
     483 */ 
     484public function admin_page () 
    613485{ 
    614486    global $sr_options, $notations; 
     
    617489    { 
    618490        check_admin_referer ('scorerender-update-options'); 
    619         scorerender_remove_cache(); 
     491        $this->remove_cache(); 
    620492    } 
    621493 
     
    623495    { 
    624496        check_admin_referer ('scorerender-update-options'); 
    625         scorerender_update_options(); 
    626     } 
    627 ?> 
    628  
    629     <div class="wrap"> 
     497        $this->update_options(); 
     498    } 
     499?> 
     500<div class="wrap"> 
     501    <?php if ( function_exists ('screen_icon') ) screen_icon(); ?> 
     502    <h2><?php _e('ScoreRender options', TEXTDOMAIN) ?> <a href="javascript:" title="<?php _e('Click to show help') ?>" onclick="jQuery('#sr-help-1').slideToggle('fast');"><img src="<?php echo plugins_url ('scorerender/images/info-icon.png'); ?>" width="32" height="32" class="sr-help-icon" /></a></h2> 
     503 
    630504    <form method="post" action="" id="scorerender-conf"> 
    631505    <?php wp_nonce_field ('scorerender-update-options') ?> 
    632     <h2><?php _e('ScoreRender options', TEXTDOMAIN) ?></h2> 
    633  
    634     <p><?php _e('ScoreRender renders inline music fragments inside blog post and/or comment as images. Currently it supports the following notations (each notation name is followed by its starting and ending tag):', TEXTDOMAIN); ?></p> 
    635     <ul> 
    636         <li><a target="_blank" href="http://www.lilypond.org/">Lilypond</a> 
    637         (<?php printf ('<code>%s</code>, <code>%s</code>', $notations['lilypond']['starttag'], $notations['lilypond']['endtag']); ?>)</li> 
    638         <li><a target="_blank" href="http://www.arkkra.com/">Mup</a> 
    639         (<?php printf ('<code>%s</code>, <code>%s</code>', $notations['mup']['starttag'], $notations['mup']['endtag']); ?>) 
    640         <?php printf ('Used by Mup itself and %s', '<a target="_blank" href="http://noteedit.berlios.de/">Noteedit</a>'); ?></li> 
    641         <li><a target="_blank" href="http://www.informatik.tu-darmstadt.de/AFS/GUIDO/">GUIDO</a> 
    642         (<?php printf ('<code>%s</code>, <code>%s</code>', $notations['guido']['starttag'], $notations['guido']['endtag']); ?>)</li> 
    643         <li><a target="_blank" href="http://abcnotation.org.uk/">ABC</a> 
    644         (<?php printf ('<code>%s</code>, <code>%s</code>', $notations['abc']['starttag'], $notations['abc']['endtag']); ?>) 
    645         <?php printf ('Used by various programs like %s, %s or %s', 
    646             '<a target="_blank" href="http://www.ihp-ffo.de/~msm/">abc2ps</a>', 
    647             '<a target="_blank" href="http://moinejf.free.fr/">abcm2ps</a>', 
    648             '<a target="_blank" href="http://trillian.mit.edu/~jc/music/abc/src/">jcabc2ps</a>'); ?></li> 
    649         <li><a target="_blank" href="http://www.quercite.com/pmw.html">Philip's Music Writer</a> 
    650         (<?php printf ('<code>%s</code>, <code>%s</code>', $notations['pmw']['starttag'], $notations['pmw']['endtag']); ?>)</li> 
    651     </ul> 
     506 
     507    <div id="sr-help-1" class="hidden"> 
     508        <p><?php _e('ImageMagick &ge; 6.3.6-2 must be present and working (specifically, the <code>convert</code> program). For each kind of notation, leaving corresponding program location empty means disabling that notation support automatically, except GUIDO which does not use any program.', TEXTDOMAIN); ?></p> 
     509 
     510        <p><?php _e('The following notations are supported by ScoreRender, along with starting and ending shortcode after each notation name. Each music fragment must be enclosed by corresponding pair of shortcodes. Click on the links to read more about each notation.', TEXTDOMAIN); ?></p> 
     511        <ul> 
     512<?php   foreach ($notations as $tag => $notation_data) : ?> 
     513        <li><a target="_blank" href="<?php echo $notation_data['url']; ?>"><?php echo $notation_data['name']; ?></a> 
     514        (<code><?php echo $notation_data['starttag']; ?></code>, <code><?php echo $notation_data['endtag']; ?></code>)</li> 
     515<?php   endforeach; ?> 
     516        </ul> 
     517    </div> 
    652518 
    653519<?php 
    654520    // path options 
    655     scorerender_admin_section_path(); 
     521    $this->admin_section_path(); 
    656522 
    657523    // program location options 
    658     scorerender_admin_section_prog(); 
     524    $this->admin_section_prog(); 
    659525 
    660526    // image options 
    661     scorerender_admin_section_image(); 
     527    $this->admin_section_image(); 
    662528 
    663529    // content options 
    664     scorerender_admin_section_content(); 
     530    $this->admin_section_content(); 
    665531 
    666532    // caching options 
    667     scorerender_admin_section_caching(); 
     533    $this->admin_section_caching(); 
    668534?> 
    669535    <p class="submit"> 
    670     <input type="submit" name="Submit" value="<?php _e('Update Options &raquo;', TEXTDOMAIN) ?>" /> 
     536    <input type="submit" name="Submit" class="button-primary" value="<?php _e('Update Options &raquo;', TEXTDOMAIN) ?>" /> 
    671537    </p> 
    672538 
    673     </div> 
    674539    </form> 
     540</div> 
    675541    <?php 
    676542} 
    677543 
    678544/** 
     545 * Add 'Settings' link to entry in global plugin admin page, alongside the 
     546 * Activate/Deactivate links. This is used as a WP hook. 
     547 * 
     548 * @param array $links Reference to array of links shown on plugin admin page 
     549 * @param string $file Part of plugin file name under plugin dir 
     550 * @since 0.3.50 
     551 */ 
     552public function settings_link ($links, $file) 
     553{ 
     554    if ( $file == 'scorerender/wp-scorerender.php' ) 
     555        if ( function_exists ('admin_url') ) 
     556            $links[] = sprintf ('<a href="%s">%s</a>', 
     557                    admin_url ('options-general.php?page=scorerender'), 
     558                    __('Settings')  // use global WP translation 
     559                   ); 
     560    return $links; 
     561} 
     562 
     563/** 
    679564 * Append submenu item into WordPress menu 
    680565 * 
    681  * @access private 
    682  */ 
    683 function scorerender_admin_menu () 
    684 { 
    685     add_options_page (__('ScoreRender options', TEXTDOMAIN), 'ScoreRender', 9, __FILE__, 'scorerender_admin_options'); 
    686 } 
    687  
    688  
    689 if ( 0 != get_option('use_balanceTags') ) 
    690 { 
    691     /** 
    692      * @ignore 
    693      */ 
    694     function sr_turn_off_balance_tags() 
    695     { 
    696         echo '<div id="balancetag-warning" class="updated" style="background-color: #ff6666"><p>' 
    697             . sprintf (__('<strong>OPTION CONFLICT</strong>: The &#8216;correct invalidly nested XHTML automatically&#8217; option conflicts with ScoreRender plugin, because it will mangle certain Lilypond and Mup fragments. The option is available in <a href="%s">Writing option page</a>.', TEXTDOMAIN), "options-writing.php") 
    698             . "</p></div>"; 
    699     } 
    700     add_filter ('admin_notices', 'sr_turn_off_balance_tags'); 
    701 } 
    702  
    703 add_filter ('activity_box_end', 'scorerender_activity_box'); 
    704 add_filter ('admin_menu', 'scorerender_admin_menu'); 
    705  
    706 ?> 
     566 * @uses ScoreRenderAdmin::admin_head() 
     567 * @uses ScoreRenderAdmin::admin_footer() 
     568 * @uses ScoreRenderAdmin::admin_page() 
     569 */ 
     570public function register_admin_page () 
     571{ 
     572    $plugin_page = add_options_page (__('ScoreRender options', TEXTDOMAIN), 'ScoreRender', 
     573            'manage_options', 'scorerender', array (&$this, 'admin_page')); 
     574    add_action('admin_head-' . $plugin_page, array (&$this, 'admin_head')); 
     575    // not using print_scripts hooks, not sanitized until WP 2.8 
     576    add_action('admin_footer-' . $plugin_page, array (&$this, 'admin_footer')); 
     577} 
     578 
     579/** 
     580 * Output warning to tell users to turn off 'correct invalidly nested 
     581 * XHTML automatically' option. 
     582 */ 
     583public function turn_off_balance_tags() 
     584{ 
     585    echo '<div id="balancetag-warning" class="error"><p>' . 
     586        sprintf (__('<strong>OPTION CONFLICT</strong>: The &#8216;correct invalidly nested XHTML automatically&#8217; option conflicts with ScoreRender plugin, because it will mangle certain Lilypond and Mup fragments. The option is available in <a href="%s">Writing option page</a>.', TEXTDOMAIN), "options-writing.php") . 
     587        "</p></div>"; 
     588} 
     589 
     590/** 
     591 * Class constructor, for adding wordpress admin related hooks 
     592 * 
     593 * @uses ScoreRenderAdmin::register_admin_page() 
     594 * @uses ScoreRenderAdmin::settings_link() 
     595 * @uses ScoreRenderAdmin::turn_off_balance_tags() 
     596 * @access private 
     597 */ 
     598public function __construct () 
     599{ 
     600    add_action ('admin_menu',            array (&$this, 'register_admin_page')); 
     601    add_filter ('plugin_action_links',   array (&$this, 'settings_link'), 10, 2); 
     602    if ( 0 != get_option('use_balanceTags') ) 
     603        add_action ('admin_notices', array (&$this, 'turn_off_balance_tags')); 
     604 
     605} 
     606 
     607} // end class 
     608 
     609global $sr_admin; 
     610$sr_admin = new ScoreRenderAdmin(); 
     611 
     612?> 
  • scorerender/trunk/scorerender-class.php

    r114489 r209432  
    11<?php 
    2 /* 
    3  * Methods implementable by subclasses: 
    4  * 
    5  * Mandatory: 
    6  * - conversion_step1($input_file, $intermediate_image) 
    7  * - get_music_fragment($input) 
    8  * - conversion_step2($intermediate_image, $final_image, $invert, $transparent) 
    9  *   --- this one most usually invokes parent converting() 
    10  * 
    11  * Optional: 
    12  * - is_valid_input() 
    13  * 
    14  * Please refer to class.*.inc.php for examples. 
    15 */ 
    16  
    172/** 
    183 * ScoreRender documentation 
    194 * @package ScoreRender 
    20  */ 
    21  
    22 /** 
    23  * ScoreRender Class 
     5 * @version 0.3.50 
     6 * @author Abel Cheung <abelcheung at gmail dot com> 
     7 * @copyright Copyright (C) 2006 Chris Lamb <chris at chris-lamb dot co dot uk> 
     8 * @copyright Copyright (C) 2007, 2008, 2009, 2010 Abel Cheung 
     9 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU AGPL v3 
     10 */ 
     11 
     12/** 
     13 * Base class shared by all notations. 
     14 * Most mandatory subclass methods are already listed in  
     15 * {@link ScoreRender_Notation} interface below, plus one more: 
     16 * 
     17 * - {@link conversion_step1()} 
     18 * 
     19 * The methods below are optional for subclasses: 
     20 * 
     21 * - {@link conversion_step2()} 
     22 * - {@link is_valid_input()} 
     23 * 
     24 * Please refer to class.*.inc.php for examples. 
    2425 * @package ScoreRender 
    2526 */ 
    2627abstract class ScoreRender 
    2728{ 
    28  
    29 /* 
    30  * Error constants 
    31  */ 
    3229 
    3330/** 
     
    3734 * inclusion of another file or command execution, etc. 
    3835 */ 
    39 const ERR_INVALID_INPUT = -1; 
     36const ERR_INVALID_INPUT = 1; 
    4037 
    4138/** 
    4239 * Error constant used when cache directory is not writable. 
    4340 */ 
    44 const ERR_CACHE_DIRECTORY_NOT_WRITABLE = -2; 
     41const ERR_CACHE_DIRECTORY_NOT_WRITABLE = 2; 
    4542 
    4643/** 
    4744 * Error constant used when temporary working directory is not writable. 
    4845 */ 
    49 const ERR_TEMP_DIRECTORY_NOT_WRITABLE = -3; 
     46const ERR_TEMP_DIRECTORY_NOT_WRITABLE = 3; 
    5047 
    5148/** 
     
    5451 * This error is very rare, most usually it's the directory (not file) which is not writable. 
    5552 */ 
    56 const ERR_TEMP_FILE_NOT_WRITABLE = -4; 
     53const ERR_TEMP_FILE_NOT_WRITABLE = 4; 
    5754 
    5855/** 
    5956 * Error constant used when conversion of rendered image to proper format (PostScript -> PNG) failed. 
    6057 */ 
    61 const ERR_IMAGE_CONVERT_FAILURE = -5; 
     58const ERR_IMAGE_CONVERT_FAILURE = 5; 
    6259 
    6360/** 
    6461 * Error constant used when any generic error occurred during rendering. 
    6562 */ 
    66 const ERR_RENDERING_ERROR = -6; 
    67  
    68 /** 
    69  * Error constant used when length of supplied content exceeds configured limit. 
    70  */ 
    71 const ERR_LENGTH_EXCEEDED = -7; 
    72  
    73 /** 
    74  * Error constant representing internal class error. 
    75  * 
    76  * Currently used when some essential method is not implemented in classes. 
    77  */ 
    78 const ERR_INTERNAL_CLASS = -8; 
     63const ERR_RENDERING_ERROR = 6; 
    7964 
    8065/** 
    8166 * Error constant representing that ImageMagick convert is unusable. 
    8267 */ 
    83 const ERR_CONVERT_UNUSABLE = -9; 
     68const ERR_CONVERT_UNUSABLE = 9; 
    8469 
    8570/** 
    8671 * Error constant representing final image unreadable. 
    8772 */ 
    88 const ERR_IMAGE_NOT_VIEWABLE = -10; 
     73const ERR_IMAGE_NOT_VIEWABLE = 10; 
    8974 
    9075/** 
    9176 * Error constant representing web host disabled certain PHP functions 
    9277 */ 
    93 const ERR_FUNC_DISABLED = -11; 
     78const ERR_FUNC_DISABLED = 11; 
    9479 
    9580 
     
    11095 
    11196/** 
    112  * @var boolean $is_inverted Whether image should be rendered in white on black. 
    113  */ 
    114 protected $is_inverted = false; 
    115  
    116 /** 
    117  * @var boolean $is_transparent Whether rendered image should use transparent background. 
    118  */ 
    119 protected $is_transparent = true; 
    120  
    121 /** 
    12297 * @var string $imagemagick Full path of ImageMagick convert 
    12398 */ 
     
    133108 */ 
    134109protected $cache_dir; 
    135  
    136 /** 
    137  * @var integer $content_max_length Maximum length of score fragment source (in bytes) 
    138  */ 
    139 protected $content_max_length = 4096; 
    140110 
    141111/** 
     
    177147 * @uses $mainprog Full path is stored in this variable 
    178148 * @todo For some notations like PMX/MusiXTeX, multiple programs must be set, currently this function can only handle one. 
    179  * @since 0.2.50 
     149 * @since 0.3 
    180150 */ 
    181151public function set_programs ($progs) 
     
    206176 
    207177/** 
    208  * Outputs music fragment content 
    209  * 
    210  * Most usually user supplied content does not contain correct 
    211  * rendering options like page margin, staff width etc, and 
    212  * each notation has its own requirements. Some also require additional 
    213  * filtering before able to be used by rendering programs. 
    214  * Such conversions are applied on output as well, though original content 
    215  * ($_input) is not modified in any way. 
    216  * 
    217  * @uses $_input 
    218  * @return string The full music content to be rendered, after necessary filtering 
    219  */ 
    220 abstract public function get_music_fragment (); 
    221  
    222 /** 
    223178 * Returns output message of rendering command. 
    224179 * 
     
    235190 * 
    236191 * @return string|boolean Return notation name if found, FALSE otherwise. 
     192 * @uses format_error_msg() 
    237193 * @since 0.2 
    238194 */ 
     
    246202            return $notationname; 
    247203 
    248     throw new Exception ( $this->format_error_msg ( 
    249         __('Unknown notation type!', TEXTDOMAIN) ) ); 
    250204    return false; 
    251205} 
     
    255209 * 
    256210 * @param string $path Full path of ImageMagick convert binary 
    257  * @since 0.2.50 
     211 * @since 0.3 
    258212 */ 
    259213public function set_imagemagick_path ($path) 
     
    263217 
    264218/** 
    265  * Sets whether inverted image shall be generated 
    266  * 
    267  * @param boolean $invert White note is rendered if TRUE, black otherwise. 
    268  * @since 0.2.50 
    269  */ 
    270 public function set_inverted ($invert) 
    271 { 
    272     $this->is_inverted = $invert; 
    273 } 
    274  
    275 /** 
    276  * Sets whether transparent image shall be used 
    277  * 
    278  * @param boolean $transparent Use transparent background if TRUE, black or white otherwise. 
    279  * @since 0.2.50 
    280  */ 
    281 public function set_transparency ($transparent) 
    282 { 
    283     $this->is_transparent = $transparent; 
    284 } 
    285  
    286 /** 
    287219 * Set temporary folder 
    288220 * 
    289221 * @param string $path The desired temporary folder to use. 
    290  * @since 0.2.50 
     222 * @since 0.3 
    291223 */ 
    292224public function set_temp_dir ($path) 
     
    299231 * 
    300232 * @return string|boolean The temporary folder if already set, or FALSE otherwise 
    301  * @since 0.2.50 
     233 * @since 0.3 
    302234 */ 
    303235public function get_temp_dir () 
     
    310242 * 
    311243 * @param string $path The desired cache folder to use. 
    312  * @since 0.2.50 
     244 * @since 0.3 
    313245 */ 
    314246public function set_cache_dir ($path) 
     
    321253 * 
    322254 * @return string|boolean The cache folder if already set, or FALSE otherwise 
    323  * @since 0.2.50 
     255 * @since 0.3 
    324256 */ 
    325257public function get_cache_dir () 
    326258{ 
    327259    return (isset ($this->cache_dir)) ? $this->cache_dir : false; 
    328 } 
    329  
    330 /** 
    331  * Set maximum allowed length of score fragment source 
    332  * 
    333  * @param integer $length Maximum length of score fragment source (in byte) 
    334  * @since 0.2.50 
    335  */ 
    336 public function set_max_length ($length) 
    337 { 
    338     $this->content_max_length = $length; 
    339260} 
    340261 
     
    346267 * 
    347268 * @param integer $width Maximum width of images (in pixel) 
    348  * @since 0.2.50 
     269 * @since 0.3 
    349270 */ 
    350271public function set_img_width ($width) 
     
    358279 * @param string $mesg Original error message 
    359280 * @return string Formatted message 
    360  * @since 0.2.50 
     281 * @since 0.3 
    361282 */ 
    362283private function format_error_msg ($mesg) 
    363284{ 
    364     return sprintf (__('[%s: %s]', TEXTDOMAIN), 
    365         __('ScoreRender Error', TEXTDOMAIN), $mesg); 
     285    return sprintf (__('[ScoreRender Error: %s]', TEXTDOMAIN), $mesg); 
    366286} 
    367287 
     
    370290 * 
    371291 * @uses $error_code Message is generated according to error code 
     292 * @uses format_error_msg() 
    372293 * @return string Localized error message 
    373  * @since 0.2.50 
     294 * @since 0.3 
    374295 */ 
    375296public function get_error_msg () 
     
    395316        return $this->format_error_msg (__('The external rendering application failed!', TEXTDOMAIN)); 
    396317 
    397       case ERR_LENGTH_EXCEEDED: 
    398         return $this->format_error_msg (__('Content length limit exceeded!', TEXTDOMAIN)); 
    399  
    400       case ERR_INTERNAL_CLASS: 
    401         return $this->format_error_msg (__('Internal class initialization error!', TEXTDOMAIN)); 
    402  
    403318      case ERR_CONVERT_UNUSABLE: 
    404319        return $this->format_error_msg (__('ImageMagick program is unusable!', TEXTDOMAIN)); 
     
    406321      case ERR_IMAGE_NOT_VIEWABLE: 
    407322        return $this->format_error_msg (__('Image is not viewable!', TEXTDOMAIN)); 
     323 
    408324      case ERR_FUNC_DISABLED: 
    409325        return $this->format_error_msg (__('Some PHP functions are disabled by web host.', TEXTDOMAIN)); 
     
    420336 * @param string $cmd Command to be executed 
    421337 * @uses $_commandOutput Command output is stored after execution. 
    422  * @return integer Exit status of the command. 
     338 * @uses is_windows() Command line is adjusted if under Windows 
     339 * @return integer Exit status of the command 
    423340 * @final 
    424341 */ 
    425342final protected function _exec ($cmd) 
    426343{ 
    427     if (DEBUG) { echo '<pre style="overflow: auto">' . $cmd . "</pre>\n"; } 
     344    if (SR_DEBUG) { echo '<pre style="overflow: auto">' . $cmd . "</pre>\n"; } 
    428345 
    429346    $cmd_output = array(); 
     
    469386 * @uses _exec() 
    470387 * @uses $imagemagick 
    471  * @uses $is_inverted 
    472  * @uses $is_transparent 
    473388 * @param string $intermediate_image The rendered PostScript file name 
    474389 * @param string $final_image The final PNG image file name 
     
    485400    if ($ps_has_alpha) 
    486401    { 
    487         if ($this->is_transparent) 
    488             $cmd .= sprintf (' %s "%s" "%s"', 
    489                 (($this->is_inverted) ? '-negate' : ''), 
    490                 $intermediate_image, $final_image); 
    491         else 
    492             $cmd .= sprintf (' -flatten "%s" png:- | "%s" -alpha deactivate %s png:- "%s"', 
    493                 $intermediate_image, 
    494                 $this->imagemagick, 
    495                 (($this->is_inverted) ? '-negate' : ''), 
    496                 $final_image); 
     402        $cmd .= sprintf (' "%s" "%s"', 
     403            $intermediate_image, $final_image); 
    497404    } 
    498405    else 
    499406    { 
    500         if (!$this->is_transparent) 
    501             $cmd .= sprintf (' %s "%s" "%s"', 
    502                 (($this->is_inverted) ? '-negate' : ''), 
    503                 $intermediate_image, $final_image); 
    504         else 
    505         { 
    506             // Adding alpha channel and changing alpha value 
    507             // need separate invocations, can't do in one pass 
    508             $cmd .= sprintf ('-alpha activate "%s" png:- | "%s" -channel alpha -fx "1-intensity" -channel rgb -fx %d png:- "%s"', 
    509                 $intermediate_image, 
    510                 $this->imagemagick, 
    511                 (($this->is_inverted)? 1 : 0), 
    512                 $final_image); 
    513         } 
     407        // Adding alpha channel and changing alpha value 
     408        // need separate invocations, can't do in one pass 
     409        $cmd .= sprintf ('-alpha activate "%s" png:- | "%s" -channel alpha -fx "1-intensity" -channel rgb -fx 0 png:- "%s"', 
     410            $intermediate_image, 
     411            $this->imagemagick, 
     412            $final_image); 
    514413    } 
    515414 
     
    520419 * Check if certain functions are disabled 
    521420 * 
    522  * @since 0.2.50 
    523  * @return boolean Return TRUE if popen() or pclose() are disabled, FALSE otherwise 
    524  */ 
    525 public function is_web_hosting () 
     421 * @since 0.3 
     422 * @return boolean Return TRUE if {@link popen() popen()} or 
     423 * {@link pclose() pclose()} are disabled, FALSE otherwise 
     424 */ 
     425public static function is_web_hosting () 
    526426{ 
    527427    if (!function_exists ('popen') || 
     
    535435 * @since 0.2 
    536436 * @uses is_absolute_path() 
    537  * @param mixed $match The string to be searched in program output. Can be an array of strings, in this case all strings must be found. Any non-string element in the array is ignored. 
     437 * @uses is_web_hosting() 
     438 * @param mixed $match The string to be searched in program output. 
     439 * Can be an array of strings, in this case all strings must be found. 
     440 * Any non-string element in the array is ignored. 
    538441 * @param string $prog The program to be checked 
    539442 * @param string $args Extra variable arguments supplied to the program (if any) 
    540443 * @return boolean Return TRUE if the given program is usable, FALSE otherwise 
    541444 */ 
    542 public function is_prog_usable ($match, $prog) 
     445public static function is_prog_usable ($match, $prog) 
    543446{ 
    544447    if (empty ($prog)) return false; 
     
    564467 
    565468    $output = fread ($handle, 2048); 
    566     $ok = true; 
     469    $ok = false; 
    567470 
    568471    $needles = (array) $match; 
    569472    foreach ($needles as $needle) 
    570473    { 
    571         if (is_string ($needle) && (false === strpos ($output, $needle))) 
     474        if (is_string ($needle) && (false !== strpos ($output, $needle))) 
    572475        { 
    573             $ok = false; 
     476            $ok = true; 
    574477            break; 
    575478        } 
     
    586489 * First it tries to check if image is already rendered, and return 
    587490 * existing image file name immediately. Otherwise the music fragment is 
    588  * rendered in 2 passes (with {@link conversion_step1} and {@link conversion_step2}, 
    589  * and resulting image is stored in cache folder. Error code will be 
    590  * set appropriately 
    591  * 
    592  * @uses get_music_fragment() Obtain music content from this method 
     491 * rendered in 2 passes (with {@link conversion_step1()} and 
     492 * {@link conversion_step2()}, and resulting image is stored in cache folder. 
     493 * Error code will be set appropriately. 
     494 * 
     495 * @uses ScoreRender_Notation::get_music_fragment() 
    593496 * @uses is_valid_input() Validate content before rendering 
    594497 * @uses is_prog_usable() Check if ImageMagick is functional 
    595498 * @uses conversion_step1() First pass rendering: Convert input file -> PS 
    596499 * @uses conversion_step2() Second pass rendering: Convert PS -> PNG 
     500 * @uses $_input 
     501 * @uses $cache_dir 
    597502 * @uses $error_code Type of error encountered is stored here 
    598  * @uses $cache_dir 
    599  * @uses $temp_dir 
    600  * @uses $content_max_length Content length is checked here 
    601  * 
     503 * 
     504 * @todo render image in background, especially for lilypond, which can take 
     505 * minutes or even hours to finish rendering 
    602506 * @return string|boolean Resulting image file name, or FALSE upon error 
    603507 * @final 
     
    605509final public function render() 
    606510{ 
    607     $hash = md5 ($this->_input . $this->is_inverted 
    608              . $this->is_transparent . $this->get_notation_name()); 
     511    $hash = md5 (preg_replace ('/\s/', '', $this->_input)); 
    609512    $final_image = $this->cache_dir. DIRECTORY_SEPARATOR . 
    610513               "sr-" . $this->get_notation_name() . "-$hash.png"; 
    611514 
    612     // Need not check anything if cache exists 
     515    // If cache exists, short circuit 
    613516    if (is_file ($final_image)) 
    614517        if (is_readable ($final_image)) 
     
    620523        } 
    621524 
    622     // missing class methods 
    623     if (! method_exists ($this, 'conversion_step1'  ) || 
    624         ! method_exists ($this, 'get_music_fragment')) 
    625     { 
    626         $this->error_code = ERR_INTERNAL_CLASS; 
    627         return false; 
    628     } 
    629  
    630     // Check for valid code 
     525    // Check for code validity or security issues 
    631526    if ( empty ($this->_input) || 
    632527        ( method_exists ($this, 'is_valid_input') && !$this->is_valid_input() ) ) 
    633528    { 
    634529        $this->error_code = ERR_INVALID_INPUT; 
    635         return false; 
    636     } 
    637  
    638     // Check for content length 
    639     if ( isset ($this->content_max_length) && 
    640          ($this->content_max_length > 0) && 
    641          (strlen ($this->_input) > $this->content_max_length) ) 
    642     { 
    643         $this->error_code = ERR_LENGTH_EXCEEDED; 
    644530        return false; 
    645531    } 
     
    713599        (filesize ($intermediate_image)) === 0) 
    714600    { 
    715         if (! DEBUG) { 
     601        if (! SR_DEBUG) { 
    716602            unlink ($input_file); 
    717603            @rmdir ($temp_working_dir); 
     
    729615 
    730616    // Cleanup 
    731     if (! DEBUG) { 
     617    if (! SR_DEBUG) { 
    732618        unlink ($intermediate_image); 
    733619        unlink ($input_file); 
     
    738624} 
    739625 
     626/** 
     627 * Output program setting HTML for notation 
     628 * 
     629 * @param string $bin_name Name of binary program 
     630 * @param string $setting_name Name of setting used by the binary 
     631 * @param string $title Title for setting entry 
     632 * @param string $desc Optional description, shown under setting entry 
     633 * 
     634 * @return string HTML for the program setting in admin page 
     635 * @since 0.3.50 
     636 */ 
     637public static function program_setting_entry ($bin_name, $setting_name, $title = '', $desc = '') 
     638{ 
     639    global $sr_options; 
     640    $id = strtolower ($setting_name); 
     641 
     642    $output = "<tr valign='top'>\n" 
     643        . "<th scope='row'><label for='{$id}'>" 
     644        . ( empty ($title) ? sprintf (__('Location of %s binary:', TEXTDOMAIN), '<code>'.$bin_name.'</code>') : $title ) 
     645        . "</label></th>\n" 
     646        . "<td><input name='ScoreRender[{$setting_name}]' type='text' id='{$id}' " 
     647        . "value='{$sr_options[$setting_name]}' class='regular-text code' />" 
     648        . ( empty ($desc) ? '' : "<div class='setting-description'>{$desc}</div>\n" ) 
     649        . "</td>\n</tr>\n"; 
     650 
     651    return $output; 
     652} 
     653 
    740654} // end of class 
    741655 
     656/** 
     657 * Interface for every notations used by ScoreRender 
     658 * @package ScoreRender 
     659 */ 
     660interface ScoreRender_Notation 
     661{ 
     662    /** 
     663     * Outputs music fragment content 
     664     * 
     665     * Most usually user supplied content does not contain correct 
     666     * rendering options like page margin, staff width etc, and 
     667     * each notation has its own requirements. Some also require additional 
     668     * filtering before able to be used by rendering programs. 
     669     * Such conversions are applied on output as well, though original content 
     670     * ($_input) is not modified in any way. 
     671     * 
     672     * @return string The full music content to be rendered, after necessary filtering 
     673     */ 
     674    function get_music_fragment (); 
     675 
     676    /** 
     677     * Check if given program locations are correct and usable 
     678     * 
     679     * @param array $errmsgs An array of messages to be added if program checking failed 
     680     * @param array $opt Reference of ScoreRender option array, containing all program paths 
     681     * 
     682     * @since 0.3.50 
     683     */ 
     684    static function is_notation_usable ($errmsgs, $opt); 
     685 
     686    /** 
     687     * Define any additional error or warning messages if settings for notation 
     688     * has any problem. 
     689     * 
     690     * @param array $adm_msgs Array of messages potentially shown in 
     691     * admin page if any problem occurs 
     692     * 
     693     * @since 0.3.50 
     694     */ 
     695    static function define_admin_messages ($adm_msgs); 
     696 
     697    /** 
     698     * Output program setting HTML for notation 
     699     * 
     700     * @param string $output string containing all HTML output, where extra settings shall be added 
     701     * @return string The new HTML output after adding input entries for settings 
     702     * 
     703     * @since 0.3.50 
     704     */ 
     705    static function program_setting_entry ($output); 
     706 
     707    /** 
     708     * Define types of variables used for notation 
     709     * 
     710     * @param array $settings Reference of ScoreRender default settings to be modified 
     711     * 
     712     * @since 0.3.50 
     713     */ 
     714    static function define_setting_type ($settings); 
     715 
     716    /** 
     717     * Define values for variables used for notation, usually program paths 
     718     * 
     719     * @param array $settings Reference of ScoreRender default settings to be modified 
     720     * 
     721     * @since 0.3.50 
     722     */ 
     723    static function define_setting_value ($settings); 
     724 
     725} // end of interface 
     726 
    742727?> 
  • scorerender/trunk/scorerender-utils.php

    r114489 r209432  
    44 * ScoreRender documentation 
    55 * @package ScoreRender 
    6  * @version 0.2.50 
     6 * @version 0.3.50 
    77 * @author Abel Cheung <abelcheung at gmail dot com> 
    88 * @copyright Copyright (C) 2006 Chris Lamb <chris at chris-lamb dot co dot uk> 
    9  * @copyright Copyright (C) 2007, 08 Abel Cheung 
    10  * @license http://opensource.org/licenses/gpl-license.php GNU Public License 
     9 * @copyright Copyright (C) 2007, 2008, 2009, 2010 Abel Cheung 
     10 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU AGPL v3 
    1111 */ 
    1212 
    13 // 
    1413// Backported function: sys_get_temp_dir 
    1514// http://www.phpit.net/article/creating-zip-tar-archives-dynamically-php/2/ 
     
    4140} 
    4241 
    43 // 
    4442// Backported function: array_intersect_key 
    4543// http://www.php.net/manual/en/function.array-intersect-key.php#68179 
     
    6260} 
    6361 
    64 // Backported function: wp_parse_str 
    65 // Not available on WP 2.2 
    66 if (!function_exists ('wp_parse_str')) { 
    67     function wp_parse_str( $string, &$array ) { 
    68         parse_str( $string, $array ); 
    69         if ( get_magic_quotes_gpc() ) 
    70             $array = stripslashes_deep( $array ); // parse_str() adds slashes if magicquotes is on.  See: http://php.net/parse_str 
    71         $array = apply_filters( 'wp_parse_str', $array ); 
    72     } 
    73 } 
    74  
    7562/** 
    7663 * Convenience function: Check if OS is Windows 
    7764 * 
    78  * @since 0.2.50 
     65 * @since 0.3 
    7966 * return boolean True if OS is Windows, false otherwise. 
    8067 */ 
     
    8875 * Transform path string to Windows or Unix presentation 
    8976 * 
    90  * @since 0.2.50 
     77 * @since 0.3 
    9178 * @param string $path The path to be transformed 
    9279 * @param boolean $is_internal Whether to always transform into Unix format, which is used for storing values into database. FALSE means using OS native representation. 
    93  * @uses is_windows 
     80 * @uses is_windows() 
    9481 * @return string $path The resulting path, with appropriate slashes or backslashes 
    9582 */ 
     
    10693 * Convenience function: Check if a path is aboslute path 
    10794 * 
    108  * @since 0.2.50 
     95 * @since 0.3 
     96 * @uses is_windows() 
    10997 * @return boolean True if path is absolute, false otherwise. 
    11098 */ 
     
    120108 * 
    121109 * Inspired from PHP tempnam documentation comment 
     110 * 
     111 * @uses sys_get_temp_dir() 
    122112 * @param string $dir Base directory on which temp folder is created 
    123113 * @param string $prefix Prefix of temp directory 
     
    146136} 
    147137 
     138/** 
     139 * Search program inside path and return location 
     140 * 
     141 * @since 0.3.50 
     142 * @uses is_windows() 
     143 * @param string $prog The program name to be searched 
     144 * @return string|boolean Full path of program if it is found, FALSE otherwise 
     145 */ 
     146function search_path ($prog) 
     147{ 
     148    foreach ( explode( ( is_windows() ? ';' : ':' ), 
     149            getenv('PATH')) as $dir ) { 
     150        if ( file_exists ($dir . DIRECTORY_SEPARATOR . $prog) ) 
     151            return $dir . DIRECTORY_SEPARATOR . $prog; 
     152    } 
     153 
     154    return false; 
     155} 
     156 
     157 
     158/** 
     159 * Transform all path related options in ScoreRender settings 
     160 * 
     161 * @since 0.3 
     162 * @uses get_path_presentation() 
     163 * @uses scorerender_get_def_settings() 
     164 * @param array $setting The settings to be transformed, either from 
     165 * existing setting or from newly submitted setting 
     166 * @param boolean $is_internal Whether to always transform into Unix format, 
     167 * which is used for storing values into database. 
     168 * FALSE means using OS native representation. 
     169 */ 
     170function transform_paths (&$setting, $is_internal) 
     171{ 
     172    if (!is_array ($setting)) return; 
     173     
     174    $default_settings = scorerender_get_def_settings(TYPES_ONLY); 
     175     
     176    // Transform path and program settings to unix presentation 
     177    foreach ($default_settings as $key => $type) 
     178        if ( ( ($type == 'path') || ($type == 'prog') ) && isset( $setting[$key] ) ) 
     179            $setting[$key] = get_path_presentation ($setting[$key], $is_internal); 
     180 
     181} 
     182 
    148183?> 
  • scorerender/trunk/wp-scorerender.php

    r114506 r209432  
    33Plugin Name: ScoreRender 
    44Plugin URI: http://scorerender.abelcheung.org/ 
    5 Description: Renders inline music score fragments in WordPress. Heavily based on FigureRender from Chris Lamb. 
     5Description: Renders inline music score fragments in posts and pages. 
    66Author: Abel Cheung 
    7 Version: 0.3.0 
     7Version: 0.3.50 
    88Author URI: http://me.abelcheung.org/ 
    99*/ 
     
    1212 * ScoreRender documentation 
    1313 * @package ScoreRender 
    14  * @version 0.3.0 
     14 * @version 0.3.50 
    1515 * @author Abel Cheung <abelcheung at gmail dot com> 
    1616 * @copyright Copyright (C) 2006 Chris Lamb <chris at chris-lamb dot co dot uk> 
    17  * @copyright Copyright (C) 2007-09 Abel Cheung 
    18  * @license http://opensource.org/licenses/gpl-license.php GNU Public License 
     17 * @copyright Copyright (C) 2007, 2008, 2009, 2010 Abel Cheung 
     18 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU AGPL v3 
    1919 */ 
    2020 
     
    2424 * This number must be incremented every time when option has been changed, removed or added. 
    2525 */ 
    26 define ('DATABASE_VERSION', 12); 
     26define ('DATABASE_VERSION', 17); 
    2727 
    2828/** 
     
    4444 * Debugging purpose 
    4545 */ 
    46 define (DEBUG, FALSE); 
     46define (SR_DEBUG, FALSE); 
    4747 
    4848/* 
     
    5454 
    5555define ('MSG_WARNING', 1); 
    56 define ('MSG_FATAL', 2); 
    57  
    58 define ('TYPES_ONLY', 1); 
    59 define ('VALUES_ONLY', 2); 
     56define ('MSG_FATAL'  , 2); 
     57 
     58define ('TYPES_AND_VALUES', 0); 
     59define ('TYPES_ONLY'      , 1); 
     60define ('VALUES_ONLY'     , 2); 
    6061 
    6162/* 
     
    8182 * @global array $notations 
    8283 */ 
    83 $notations = array ( 
    84     'abc'      => array ( 
    85         'regex'       => '~\[abc\](.*?)\[/abc\]~si', 
    86         'starttag'    => '[abc]', 
    87         'endtag'      => '[/abc]', 
    88         'classname'   => 'abcRender', 
    89         'includefile' => 'notation/abc.php', 
    90         'progs'       => array ('ABCM2PS_BIN')), 
    91     'guido'    => array ( 
    92         'regex'       => '~\[guido\](.*?)\[/guido\]~si', 
    93         'starttag'    => '[guido]', 
    94         'endtag'      => '[/guido]', 
    95         'classname'   => 'guidoRender', 
    96         'includefile' => 'notation/guido.php', 
    97         'progs'       => array ()), 
    98     'lilypond' => array ( 
    99         'regex'       => '~\[lilypond\](.*?)\[/lilypond\]~si', 
    100         'starttag'    => '[lilypond]', 
    101         'endtag'      => '[/lilypond]', 
    102         'classname'   => 'lilypondRender', 
    103         'includefile' => 'notation/lilypond.php', 
    104         'progs'       => array ('LILYPOND_BIN')), 
    105     'mup'      => array ( 
    106         'regex'       => '~\[mup\](.*?)\[/mup\]~si', 
    107         'starttag'    => '[mup]', 
    108         'endtag'      => '[/mup]', 
    109         'classname'   => 'mupRender', 
    110         'includefile' => 'notation/mup.php', 
    111         'progs'       => array ('MUP_BIN')), 
    112     'pmw'      => array ( 
    113         'regex'       => '~\[pmw\](.*?)\[/pmw\]~si', 
    114         'starttag'    => '[pmw]', 
    115         'endtag'      => '[/pmw]', 
    116         'classname'   => 'pmwRender', 
    117         'includefile' => 'notation/pmw.php', 
    118         'progs'       => array ('PMW_BIN')), 
    119 ); 
     84$notations = array(); 
    12085 
    12186/** 
     
    12994require_once('scorerender-class.php'); 
    13095 
    131 foreach (array_values ($notations) as $notation) 
    132 { 
    133     /** 
    134      * @ignore 
    135      */ 
    136     require_once ($notation['includefile']); 
    137 } 
     96require_once('notation/abc.php'); 
     97require_once('notation/guido.php'); 
     98require_once('notation/lilypond.php'); 
     99require_once('notation/mup.php'); 
     100require_once('notation/pmw.php'); 
    138101 
    139102/** 
    140103 * Default options used for first-time install. Also contains the type of value, 
    141104 * so other actions can be applied depending on setting type. 
    142  * @global array $default_settings 
    143  */ 
    144 function scorerender_get_def_settings ($return_type = 0) 
    145 { 
    146     // ImageMagick use versioned folders, abcm2ps don't have Win32 installer 
    147     // So just make up some close enough paths for them 
    148     // PMW doesn't even have public available Win32 binary, perhaps 
    149     // somebody might be able to compile it with MinGW? 
    150  
    151     if (is_windows ()) 
    152         $defprog = array ( 
    153             'abc2ps' => 'C:\Program Files\abcm2ps\abcm2ps.exe', 
    154             'convert' => 'C:\Program Files\ImageMagick\convert.exe', 
    155             'lilypond' => 'C:\Program Files\Lilypond\usr\bin\lilypond.exe', 
    156             'mup' => 'C:\Program Files\mupmate\mup.exe', 
    157             'pmw' => '', 
    158         ); 
    159     else 
    160         $defprog = array ( 
    161             'abc2ps' => '/usr/bin/abcm2ps', 
    162             'convert' => '/usr/bin/convert', 
    163             'lilypond' => '/usr/bin/lilypond', 
    164             'mup' => '/usr/local/bin/mup', 
    165             'pmw' => '/usr/local/bin/pmw', 
    166         ); 
    167  
    168     $cachefolder = scorerender_get_upload_dir (); 
     105 * 
     106 * @uses is_windows() Determine default program path based on operating system 
     107 * @uses sys_get_temp_dir() 
     108 */ 
     109function scorerender_get_def_settings ($return_type = TYPES_AND_VALUES) 
     110{ 
     111    $retval = array(); 
    169112 
    170113    $default_settings = array 
    171114    ( 
    172         'DB_VERSION'           => array ('type' =>   'none', 'value' => DATABASE_VERSION), 
    173         'TEMP_DIR'             => array ('type' =>   'path', 'value' => sys_get_temp_dir()), 
    174         'CACHE_DIR'            => array ('type' =>   'path', 'value' => $cachefolder['path']), 
    175         'CACHE_URL'            => array ('type' =>    'url', 'value' => $cachefolder['url']), 
    176  
    177         'IMAGE_MAX_WIDTH'      => array ('type' =>    'int', 'value' => 360), 
    178         'INVERT_IMAGE'         => array ('type' =>   'bool', 'value' => false), 
    179         'TRANSPARENT_IMAGE'    => array ('type' =>   'bool', 'value' => true), 
    180         'USE_IE6_PNG_ALPHA_FIX'=> array ('type' =>   'bool', 'value' => true), 
    181         'SHOW_SOURCE'          => array ('type' =>   'bool', 'value' => false), 
    182         'COMMENT_ENABLED'      => array ('type' =>   'bool', 'value' => false), 
    183         'ERROR_HANDLING'       => array ('type' =>   'enum', 'value' => ON_ERR_SHOW_MESSAGE), 
    184  
    185         'CONTENT_MAX_LENGTH'   => array ('type' =>    'int', 'value' => 4096), 
    186         'FRAGMENT_PER_COMMENT' => array ('type' =>    'int', 'value' => 1), 
    187  
    188         'CONVERT_BIN'          => array ('type' =>   'prog', 'value' => $defprog['convert']), 
    189         'LILYPOND_BIN'         => array ('type' =>   'prog', 'value' => $defprog['lilypond']), 
    190         'MUP_BIN'              => array ('type' =>   'prog', 'value' => $defprog['mup']), 
    191         'ABCM2PS_BIN'          => array ('type' =>   'prog', 'value' => $defprog['abc2ps']), 
    192         'PMW_BIN'              => array ('type' =>   'prog', 'value' => $defprog['pmw']), 
    193         'MUP_MAGIC_FILE'       => array ('type' =>   'path', 'value' => ''), 
     115        'DB_VERSION'           => array ('type' => 'none', 'value' => DATABASE_VERSION), 
     116        'TEMP_DIR'             => array ('type' => 'path', 'value' => sys_get_temp_dir()), 
     117        'CACHE_DIR'            => array ('type' => 'path', 'value' => ''), 
     118 
     119        'IMAGE_MAX_WIDTH'      => array ('type' =>  'int', 'value' => 360), 
     120        'NOTE_COLOR'           => array ('type' =>  'str', 'value' => '#000000'), 
     121        'USE_IE6_PNG_ALPHA_FIX'=> array ('type' => 'bool', 'value' => true), 
     122        'SHOW_SOURCE'          => array ('type' => 'bool', 'value' => false), 
     123        'COMMENT_ENABLED'      => array ('type' => 'bool', 'value' => false), 
     124        'ERROR_HANDLING'       => array ('type' => 'enum', 'value' => ON_ERR_SHOW_MESSAGE), 
     125 
     126        'FRAGMENT_PER_COMMENT' => array ('type' =>  'int', 'value' => 1), 
     127 
     128        'CONVERT_BIN'          => array ('type' => 'prog', 'value' => ''), 
     129        'MUP_REG_KEY'          => array ('type' =>  'str', 'value' => ''), 
    194130    ); 
    195131 
    196     $retval = array(); 
    197     switch ($return_type) 
    198     { 
    199       case TYPES_ONLY: 
     132    do_action_ref_array ('scorerender_define_setting_type', array(&$default_settings)); 
     133 
     134    if (TYPES_ONLY == $return_type) 
     135    { 
    200136        foreach ($default_settings as $key => $val) 
    201137            $retval += array ($key => $val['type']); 
    202138        return $retval; 
     139    } 
     140 
     141    $convert = ''; 
     142 
     143    if ( is_windows() ) 
     144    { 
     145        $convert = search_path ('convert.exe'); 
     146        if ( !$convert && function_exists ('glob') ) 
     147        { 
     148            $convert  = glob ('C:\Program Files\ImageMagick*\convert.exe'); 
     149            $convert = empty ($convert)  ? '' : $convert[0]; 
     150        } 
     151    } 
     152    else 
     153    { 
     154        if ( function_exists ('shell_exec') ) 
     155            $convert  = shell_exec ('which convert'); 
     156        else 
     157            $convert = search_path ('convert'); 
     158    } 
     159 
     160    $default_settings['CONVERT_BIN']['value'] = empty ($convert) ? '' : $convert; 
     161 
     162    do_action_ref_array ('scorerender_define_setting_value', array(&$default_settings)); 
     163 
     164    $cachefolder = wp_upload_dir (); 
     165    $default_settings['CACHE_DIR']['value'] = $cachefolder['basedir']; 
     166 
     167    switch ($return_type) 
     168    { 
    203169      case VALUES_ONLY: 
    204170        foreach ($default_settings as $key => $val) 
    205171            $retval += array ($key => $val['value']); 
    206172        return $retval; 
    207       default: 
     173      case TYPES_AND_VALUES: 
    208174        return $default_settings; 
    209175    } 
     
    230196 
    231197/** 
    232  * Transform all path related options in ScoreRender settings 
    233  * 
    234  * @since 0.2.50 
    235  * @uses get_path_presentation() 
    236  * @param array $setting The settings to be transformed, either from existing setting or from newly submitted setting 
    237  * @param boolean $is_internal Whether to always transform into Unix format, which is used for storing values into database. FALSE means using OS native representation. 
    238  */ 
    239 function transform_paths (&$setting, $is_internal) 
    240 { 
    241     if (!is_array ($setting)) return; 
    242      
    243     $default_settings = scorerender_get_def_settings(TYPES_ONLY); 
    244      
    245     // Transform path and program settings to unix presentation 
    246     foreach ($default_settings as $key => $type) 
    247         if ( ($type == 'path') || ($type == 'prog') ) 
    248             if (isset ($setting[$key])) 
    249                 $setting[$key] = get_path_presentation ($setting[$key], $is_internal); 
    250  
    251 } 
    252  
    253 /** 
    254  * Guess default upload directory setting from WordPress. 
    255  *  
    256  * WordPress is inconsistent with upload directory setting across multiple 
    257  * versions. Try to guess to most sensible setting and take that as default 
    258  * value. 
    259  * 
    260  * @since 0.2 
    261  * @uses get_path_presentation() 
    262  * @uses is_absolute_path() 
    263  * @return array Returns array containing both full path ('path' key) and corresponding URL ('url' key) 
    264  */ 
    265 function scorerender_get_upload_dir () 
    266 { 
    267     $uploads = wp_upload_dir(); 
    268      
    269     /* Path setting read order: 
    270      * 1. wp_upload_dir() 
    271      * 2. upload_path option 
    272      * 3. ABSPATH/wp-content/uploads 
    273      */ 
    274     if (isset ($uploads['basedir'])) 
    275         $path = $uploads['basedir']; 
    276     else 
    277         $path = trim(get_option('upload_path')); 
    278      
    279     if (empty ($path)) 
    280         $path = 'wp-content/uploads'; 
    281  
    282     if (!is_absolute_path ($path)) 
    283         $path = ABSPATH . $path; 
    284  
    285     /* URL setting read order: 
    286      * 1. wp_upload_dir() 
    287      * 2. upload_url_path option 
    288      * 3. $siteurl/wp-content/uploads 
    289      */ 
    290     if (isset ($uploads['baseurl'])) 
    291         $url = $uploads['baseurl']; 
    292     else 
    293         $url = trim(get_option('upload_url_path')); 
    294      
    295     if (empty ($url)) 
    296         $url = get_option('siteurl') . '/' . 
    297             str_replace (ABSPATH, '', $path); 
    298  
    299     $path = get_path_presentation ($path, FALSE); 
    300  
    301     return (array ('path' => $path, 'url' => $url)); 
    302 } 
    303  
     198 * Retrieve all default settings and merge them into ScoreRender options 
     199 * 
     200 * @uses scorerender_get_def_settings() 
     201 * @uses $sr_options 
     202 */ 
    304203function scorerender_populate_options () 
    305204{ 
     
    330229 * config and update the options in database. 
    331230 * 
    332  * @uses scorerender_get_upload_dir() 
     231 * @uses scorerender_populate_options() 
    333232 * @uses transform_paths() 
    334233 */ 
     
    357256            $sr_options['COMMENT_ENABLED'] = true; 
    358257        } 
     258    if ($sr_options['DB_VERSION'] <= 15) 
     259        if ( $sr_options['INVERT_IMAGE'] ) 
     260            $sr_options['NOTE_COLOR'] = '#FFFFFF'; 
    359261 
    360262    scorerender_populate_options (); 
     
    363265    update_option ('scorerender_options', $sr_options); 
    364266    transform_paths ($sr_options, FALSE); 
    365      
     267 
    366268    return; 
    367269} 
     
    369271 
    370272/** 
     273 * Fetches folder location used for storing cached images 
     274 * 
     275 * If users manually set cache folder, then user setting is honored; otherwise 
     276 * WordPress default upload directory will be used. 
     277 * 
     278 * @return string Cache folder location 
     279 * @since 0.3.50 
     280 */ 
     281function scorerender_get_cache_location () 
     282{ 
     283    global $sr_options; 
     284 
     285    if ( !empty ($sr_options['CACHE_DIR']) ) 
     286        return $sr_options['CACHE_DIR']; 
     287    else 
     288    { 
     289        $data = wp_upload_dir (); 
     290        return $data['basedir']; 
     291    } 
     292} 
     293 
     294 
     295/** 
    371296 * Generate HTML content from error message or rendered image 
    372297 * 
    373298 * @uses ScoreRender::render() 
    374  * @uses ScoreRender::get_notation_name() 
    375  * @uses ScoreRender::get_music_fragment() 
    376  * @uses ScoreRender::get_error_msg() 
     299 * @uses ScoreRender::get_notation_name() Used when showing original content upon error 
     300 * @uses ScoreRender::get_music_fragment() Used when showing original content upon error 
     301 * @uses ScoreRender::get_command_output() Used when showing error message upon error, and debug is on 
     302 * @uses ScoreRender::get_error_msg() Used when showing error message upon error, and debug is off 
     303 * @uses scorerender_get_cache_location() For getting cached image location and read its size 
    377304 * 
    378305 * @param object $render PHP object created for rendering relevant music fragment 
     
    393320 
    394321          case ON_ERR_SHOW_FRAGMENT: 
    395             try { 
    396                 $name = $render->get_notation_name (); 
    397             } catch (Exception $e) { 
    398                 return $e->getMessage(); 
    399             } 
    400  
    401             return $notations[$name]['starttag'] . "\n" . 
    402                 $render->get_music_fragment() . "\n" . 
    403                 $notations[$name]['endtag']; 
     322            if ( false !== ( $name = $render->get_notation_name () ) ) 
     323                return $notations[$name]['starttag'] . "\n" . 
     324                    $render->get_music_fragment() . "\n" . 
     325                    $notations[$name]['endtag']; 
     326            else 
     327                return __('[Unknown notation type]') . "\n" . 
     328                    $render->get_music_fragment(); 
    404329 
    405330          default: 
    406             if (DEBUG) 
     331            if (SR_DEBUG) 
    407332                return $render->get_command_output (); 
    408333            else 
     
    416341 
    417342    // This idea is taken from LatexRender demo site 
    418     // FIXME: completely gone berserk if folder containing this plugin is a symlink, plugin_basename() sucks 
    419343    if ($sr_options['SHOW_SOURCE']) 
    420344    { 
    421         $html = sprintf ("<form target='fragmentpopup' action='%s/%s/%s/misc/showcode.php' method='post'>\n", get_bloginfo ('home'), PLUGINDIR, dirname (plugin_basename (__FILE__))); 
    422         $html .= sprintf ("<input type='image' name='music_image' class='scorerender-image' title='%s' alt='%s' src='%s/%s' />\n", 
     345        $html = sprintf ("<form target='fragmentpopup' action='%s' method='post'>\n", plugins_url ('scorerender/misc/showcode.php')); 
     346        $html .= sprintf ("<input type='image' name='music_image' class='scorerender-image' title='%s' alt='%s' src='%s' />\n", 
    423347            __('Click on image to view source', TEXTDOMAIN), 
    424348            __('Music fragment', TEXTDOMAIN), 
    425             $sr_options['CACHE_URL'], $result); 
    426  
    427         $name = $render->get_notation_name (); 
    428  
    429         // Shouldn't reach here 
    430         if (false === $name) 
    431             return '[ScoreRender Error: Unknown notation type!]'; 
    432  
    433         $content = $notations[$name]['starttag'] . "\n" . 
    434             $render->get_music_fragment() . "\n" . 
     349            plugins_url ('scorerender/misc/tint-image.php') . '?img=' . $result ); 
     350 
     351        if ( false === ( $name = $render->get_notation_name() ) ) 
     352            // Shouldn't reach here 
     353            return __('[Unknown notation type]'); 
     354 
     355        $content = $notations[$name]['starttag'] . "\r\n" . 
     356            preg_replace ("/(?<!\r)\n/s", "\r\n", $render->get_music_fragment()) . "\r\n" . 
    435357            $notations[$name]['endtag']; 
    436358 
     
    440362    else 
    441363    { 
    442         $html .= sprintf ("<img class='scorerender-image' title='%s' alt='%s' src='%s/%s' />\n", 
     364        $dir = scorerender_get_cache_location(); 
     365        list ($width, $height, $type, $attr) = getimagesize( $dir.'/'.$result ); 
     366        $html .= sprintf ("<img class='scorerender-image' $attr title='%s' alt='%s' src='%s' />\n", 
    443367            __('Music fragment', TEXTDOMAIN), 
    444368            __('Music fragment', TEXTDOMAIN), 
    445             $sr_options['CACHE_URL'], $result); 
     369            plugins_url ('scorerender/misc/tint-image.php') . '?img=' . $result ); 
    446370    } 
    447371 
     
    452376 
    453377/** 
    454  * Generate converted HTML fragment from music notation fragment 
     378 * Initialize PHP class for corresponding music notation 
    455379 * 
    456380 * Create PHP object for each kind of matched music notation, and set 
     
    458382 * everything to {@link scorerender_process_content()} for rendering. 
    459383 * 
    460  * If no PHP class exists corresponding to certain notation, then  
     384 * If no PHP class exists corresponding to certain notation, then 
    461385 * unconverted content is returned immediately. 
    462386 * 
     
    464388 * @uses ScoreRender::set_programs() 
    465389 * @uses ScoreRender::set_imagemagick_path() 
    466  * @uses ScoreRender::set_inverted() 
    467  * @uses ScoreRender::set_transparency() 
    468390 * @uses ScoreRender::set_temp_dir() 
    469391 * @uses ScoreRender::set_cache_dir() 
    470  * @uses ScoreRender::set_max_length() 
    471392 * @uses ScoreRender::set_img_width() 
    472393 * @uses ScoreRender::set_music_fragment() 
    473  * @uses mupRender::set_magic_file() 
    474394 * 
    475395 * @param array $matches Matched music fragment in posts or comments. This variable must be supplied by {@link preg_match preg_match()} or {@link preg_match_all preg_match_all()}. Alternatively invoke this function with {@link preg_replace_callback preg_replace_callback()}. 
    476396 * @return string Either HTML content containing rendered image, or HTML error message in case rendering failed. 
    477397 */ 
    478 function scorerender_filter ($matches) 
     398function scorerender_init_class ($matches) 
    479399{ 
    480400    global $sr_options, $notations; 
     
    489409 
    490410            $progs = array(); 
    491             foreach ($notation['progs'] as $progname) { 
    492                 $progs["$progname"] = $sr_options[$progname]; 
     411            foreach (array_keys($notation['progs']) as $setting_name) { 
     412                $programs[$setting_name] = $sr_options[$setting_name]; 
    493413            } 
    494             $render->set_programs ($progs); 
     414            $render->set_programs ($programs); 
    495415 
    496416            break; 
     
    500420 
    501421    $render->set_imagemagick_path ($sr_options['CONVERT_BIN']); 
    502     $render->set_inverted ($sr_options['INVERT_IMAGE']); 
    503     $render->set_transparency ($sr_options['TRANSPARENT_IMAGE']); 
    504     $render->set_temp_dir ($sr_options['TEMP_DIR']); 
    505     $render->set_cache_dir ($sr_options['CACHE_DIR']); 
    506     $render->set_max_length ($sr_options['CONTENT_MAX_LENGTH']); 
    507     $render->set_img_width ($sr_options['IMAGE_MAX_WIDTH']); 
     422    $render->set_temp_dir         ($sr_options['TEMP_DIR']); 
     423    $render->set_img_width        ($sr_options['IMAGE_MAX_WIDTH']); 
     424    $render->set_cache_dir        (scorerender_get_cache_location()); 
    508425 
    509426    do_action ('sr_set_class_variable', $sr_options); 
     
    517434 
    518435/** 
    519  * Renders music fragments contained inside posts / comments. 
     436 * The hook attached to WordPress plugin system. 
    520437 * 
    521438 * Check if post/comment rendering should be enabled. 
    522  * If yes, then apply {@link scorerender_filter} function on $content. 
    523  * 
    524  * @uses scorerender_filter() Apply filter to content upon regular expression match 
     439 * If yes, then apply {@link scorerender_init_class} function on $content. 
     440 * 
     441 * @uses scorerender_init_class() Initialize class upon regular expression match 
    525442 * @param string $content The whole content of blog post / comment 
    526  * @param boolean $is_post Whether content is from post or comment 
     443 * @param boolean $is_post TRUE if content comes from post / page, FALSE otherwise 
    527444 * @return string Converted blog post / comment content. 
    528445 */ 
    529 function scorerender_do_conversion ($content, $is_post) 
     446function scorerender_conversion_hook ($content, $is_post) 
    530447{ 
    531448    global $sr_options, $notations, $post; 
     
    543460    { 
    544461        // unfilled program name = disable support 
    545         foreach ($notation['progs'] as $prog) 
    546             if (empty ($sr_options[$prog])) continue; 
     462        foreach (array_keys($notation['progs']) as $setting_name) 
     463            if (empty ($sr_options[$setting_name])) continue 2; 
    547464        $regex_list[] = $notation['regex']; 
    548465    }; 
     
    552469              $sr_options['FRAGMENT_PER_COMMENT']; 
    553470 
    554     return preg_replace_callback ($regex_list, 'scorerender_filter', $content, $limit); 
    555 } 
    556  
     471    return preg_replace_callback ($regex_list, 'scorerender_init_class', $content, $limit); 
     472} 
     473 
     474/** 
     475 * Adds transparent PNG support if browser is IE6 
     476 * 
     477 * The filter used for transparent PNG image comes from Twinhelix. 
     478 * This fix first adds CSS class to all images rendered by ScoreRender, 
     479 * then use IE specific filter to add fake transparency to all images 
     480 * with such CSS class. 
     481 */ 
    557482function scorerender_add_ie6_style() 
    558483{ 
    559     // FIXME: hardcoded path is not nice 
    560     $uri = get_bloginfo('url').'/'.PLUGINDIR.'/scorerender'; 
    561     $path = parse_url ($uri, PHP_URL_PATH); 
    562484?> 
    563485<!--[if lte IE 6]> 
    564486<style type="text/css"> 
    565 .scorerender-image { behavior: url(<?php echo $path; ?>/misc/iepngfix.php); } 
     487.scorerender-image { behavior: url(<?php echo plugins_url ('/scorerender/misc/iepngfix.php') ?>); } 
    566488</style> 
    567489<![endif]--> 
    568490<?php 
    569491} 
    570  
    571 if (defined ('WP_ADMIN')) 
    572     include_once ('scorerender-admin.php'); 
    573492 
    574493/* 
     
    596515add_action ('init', 'scorerender_init_textdomain'); 
    597516 
    598 // IE6 PNG translucency filter 
    599 if ($sr_options['TRANSPARENT_IMAGE'] && 
    600     $sr_options['USE_IE6_PNG_ALPHA_FIX']) 
    601     add_action ('wp_head', 'scorerender_add_ie6_style'); 
    602  
    603 // earlier than default priority, since 
    604 // smilies conversion and wptexturize() can mess up the content 
    605 add_filter ('the_excerpt' , 
    606     create_function ('$content', 
    607         'return scorerender_do_conversion ($content, TRUE);'), 
    608     2); 
    609 add_filter ('the_content' , 
    610     create_function ('$content', 
    611         'return scorerender_do_conversion ($content, TRUE);'), 
    612     2); 
    613 add_filter ('comment_text', 
    614     create_function ('$content', 
    615         'return scorerender_do_conversion ($content, FALSE);'), 
    616     2); 
     517if (defined ('WP_ADMIN')) 
     518    include_once ('scorerender-admin.php'); 
     519else 
     520{ 
     521    // IE6 PNG translucency filter 
     522    if ($sr_options['USE_IE6_PNG_ALPHA_FIX']) 
     523        add_action ('wp_head', 'scorerender_add_ie6_style'); 
     524 
     525    // earlier than default priority, since 
     526    // smilies conversion and wptexturize() can mess up the content 
     527    add_filter ('the_excerpt' , 
     528        create_function ('$content', 
     529            'return scorerender_conversion_hook ($content, TRUE);'), 
     530        2); 
     531    add_filter ('the_content' , 
     532        create_function ('$content', 
     533            'return scorerender_conversion_hook ($content, TRUE);'), 
     534        2); 
     535    add_filter ('comment_text', 
     536        create_function ('$content', 
     537            'return scorerender_conversion_hook ($content, FALSE);'), 
     538        2); 
     539} 
    617540 
    618541?> 
Note: See TracChangeset for help on using the changeset viewer.