Changeset 192


Ignore:
Timestamp:
Apr 28, 2009 1:50:33 PM (9 years ago)
Author:
mbutscher
Message:

branches/mbutscher/work:
2.0beta03

  • Option to reverse search order for scripts (global imports first)
  • Wiki-bound option to create wiki page files with ASCII-only names (does not apply to Compact Sqlite DB backend). This should also fix a problem with Windows binary installer and WikidPad help wiki on non-western Windows versions.
  • Wiki-bound option to handle missing or externally inserted page files gracefully (does not apply to Compact Sqlite DB backend)
  • New insertion "iconimage" to insert an icon into an HTML page.
  • Preview shows link target in the status bar when hovering with mouse over it like browsers do
  • Menu item "Select All" in "Edit" menu (for completeness)
  • Bug fixed: Some errors weren't recorded in error log
  • Bug fixed: stdDialog of doc page presenter did not return a value (needed for some plugins)
  • Bug fixed: Tree scrolled to wrong initial position on startup
  • Bug fixed: Windows: Spell check addon did not work due to wrong DLL find mechanism
  • Bug fixed: LossyWikiCloseDeniedException? wasn't caught and polluted error log
  • Bug fixed: Search and replace dialog for page cleared "Search" text field when "Find next" was pressed
  • Bug fixed: Wiki-wide search dialog did not focus search text field when initially shown
  • Bug fixed: Pollution of error log if moving mouse over incremental search field
Location:
branches/mbutscher/work
Files:
1 added
1 deleted
36 edited

Legend:

Unmodified
Added
Removed
  • branches/mbutscher/work/Consts.py

    r190 r192  
    2323# (2, 0, 200, 0) is 2.0final
    2424
    25 VERSION_TUPLE = ("wikidPad", 2, 0, 102, 0)
    26 VERSION_STRING = "wikidPad 2.0beta02"
     25VERSION_TUPLE = ("wikidPad", 2, 0, 103, 0)
     26VERSION_STRING = "wikidPad 2.0beta03"
    2727HOMEPAGE = u"http://wikidpad.sourceforge.net"
    2828
     
    3333
    3434# TODO Remove this soon!!!
    35 DEADBLOCKTIMEOUT = 40
     35DEADBLOCKTIMEOUT = 80
    3636
    3737
  • branches/mbutscher/work/ExceptionLogger.py

    r188 r192  
    2121                    f.write(EL._exceptionSessionTimeStamp)
    2222                    EL._timestampPrinted = True
    23                 sys.stdout.write(data)
     23                EL._previousStdOut.write(data)
    2424                f.write(data)
    2525            finally:
     
    3636def onException(typ, value, trace):
    3737    global EL
     38   
    3839    try:
    3940#         import ExceptionLogger as EL
    40 ##        traceback.print_exception(typ, value, trace, file=sys.stdout)
     41##        traceback.print_exception(typ, value, trace, file=EL._previousStdOut)
    4142        f = open(os.path.join(EL._exceptionDestDir, "WikidPad_Error.log"), "a")
    4243        try:
     
    4849            EL._exceptionOccurred = True
    4950            EL.traceback.print_exception(typ, value, trace, file=f)
    50             EL.traceback.print_exception(typ, value, trace, file=sys.stdout)
     51            EL.traceback.print_exception(typ, value, trace, file=EL._previousStdOut)
    5152        finally:
    5253            f.close()
    5354    except:
    54         print "Exception occurred during global exception handling:"
    55         EL.traceback.print_exc(file=sys.stdout)
    56         print "Original exception:"
    57         EL.traceback.print_exception(typ, value, trace, file=sys.stdout)
     55        EL._previousStdOut.write("Exception occurred during global exception handling:\n")
     56        EL.traceback.print_exc(file=EL._previousStdOut)
     57        EL._previousStdOut.write("Original exception:\n")
     58        EL.traceback.print_exception(typ, value, trace, file=EL._previousStdOut)
    5859        EL._previousExcepthook(typ, value, trace)
    5960
     
    7374   
    7475   
     76    EL._previousStdErr = sys.stderr
     77    sys.stderr = StdErrReplacement()
     78
     79    EL._previousStdOut = sys.stdout
     80    sys.stdout = StdErrReplacement()
     81
    7582    EL._previousExcepthook = sys.excepthook
    7683    sys.excepthook = onException
    7784   
    78     EL._previousStdErr = sys.stderr
    79     sys.stderr = StdErrReplacement()
    80 
  • branches/mbutscher/work/WikidPad.pot

    r190 r192  
    66msgstr ""
    77"Project-Id-Version: PACKAGE VERSION\n"
    8 "POT-Creation-Date: 2009-04-01 20:55\n"
     8"POT-Creation-Date: 2009-04-04 10:06\n"
    99"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1010"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
     
    12241224
    12251225#: WikidPad.xrc:0 lib\pwiki\AdditionalDialogs.py:1278
    1226 #: lib\pwiki\SearchAndReplaceDialogs.py:1286
     1226#: lib\pwiki\SearchAndReplaceDialogs.py:1283
    12271227msgid "Title:"
    12281228msgstr ""
     
    12761276msgstr ""
    12771277
    1278 #: WikidPad.xrc:0 lib\pwiki\SearchAndReplaceDialogs.py:780
     1278#: WikidPad.xrc:0 lib\pwiki\SearchAndReplaceDialogs.py:776
    12791279msgid "Close"
    12801280msgstr ""
    12811281
    1282 #: WikidPad.xrc:0 lib\pwiki\SearchAndReplaceDialogs.py:1503
     1282#: WikidPad.xrc:0 lib\pwiki\SearchAndReplaceDialogs.py:1500
    12831283msgid "Set page list"
    12841284msgstr ""
    12851285
    1286 #: WikidPad.xrc:0 lib\pwiki\SearchAndReplaceDialogs.py:1751
     1286#: WikidPad.xrc:0 lib\pwiki\SearchAndReplaceDialogs.py:1748
    12871287msgid "As Resultlist"
    12881288msgstr ""
    12891289
    1290 #: WikidPad.xrc:0 lib\pwiki\SearchAndReplaceDialogs.py:1756
    1291 #: lib\pwiki\SearchAndReplaceDialogs.py:1862
     1290#: WikidPad.xrc:0 lib\pwiki\SearchAndReplaceDialogs.py:1753
     1291#: lib\pwiki\SearchAndReplaceDialogs.py:1859
    12921292msgid "As Full Search"
    12931293msgstr ""
    12941294
    1295 #: WikidPad.xrc:0 lib\pwiki\SearchAndReplaceDialogs.py:2090
     1295#: WikidPad.xrc:0 lib\pwiki\SearchAndReplaceDialogs.py:2087
    12961296#: lib\pwiki\WikiHtmlView.py:626
    12971297msgid "Activate New Tab"
     
    13181318msgstr ""
    13191319
    1320 #: WikidPadStarter.py:155 lib\pwiki\SearchAndReplaceDialogs.py:654
    1321 #: lib\pwiki\SearchAndReplaceDialogs.py:911
     1320#: WikidPadStarter.py:155 lib\pwiki\SearchAndReplaceDialogs.py:650
     1321#: lib\pwiki\SearchAndReplaceDialogs.py:908
    13221322msgid "Error!"
    13231323msgstr ""
     
    36293629msgstr ""
    36303630
    3631 #: lib\pwiki\SearchAndReplaceDialogs.py:675
     3631#: lib\pwiki\SearchAndReplaceDialogs.py:671
    36323632msgid "End of document reached. Continue at beginning?"
    36333633msgstr ""
    36343634
    3635 #: lib\pwiki\SearchAndReplaceDialogs.py:677
     3635#: lib\pwiki\SearchAndReplaceDialogs.py:673
    36363636msgid "Continue at beginning?"
    36373637msgstr ""
    36383638
    3639 #: lib\pwiki\SearchAndReplaceDialogs.py:688
    3640 #: lib\pwiki\SearchAndReplaceDialogs.py:689
     3639#: lib\pwiki\SearchAndReplaceDialogs.py:684
     3640#: lib\pwiki\SearchAndReplaceDialogs.py:685
    36413641msgid "No matches found"
    36423642msgstr ""
    36433643
    3644 #: lib\pwiki\SearchAndReplaceDialogs.py:700
    3645 #: lib\pwiki\SearchAndReplaceDialogs.py:713
    3646 #: lib\pwiki\SearchAndReplaceDialogs.py:932
    3647 #: lib\pwiki\SearchAndReplaceDialogs.py:1097
    3648 #: lib\pwiki\SearchAndReplaceDialogs.py:1113
    3649 #: lib\pwiki\SearchAndReplaceDialogs.py:1161
    3650 #: lib\pwiki\SearchAndReplaceDialogs.py:1172
    3651 #: lib\pwiki\SearchAndReplaceDialogs.py:1240
    3652 #: lib\pwiki\SearchAndReplaceDialogs.py:1279
    3653 #: lib\pwiki\SearchAndReplaceDialogs.py:1433
    3654 #: lib\pwiki\SearchAndReplaceDialogs.py:2046
     3644#: lib\pwiki\SearchAndReplaceDialogs.py:696
     3645#: lib\pwiki\SearchAndReplaceDialogs.py:709
     3646#: lib\pwiki\SearchAndReplaceDialogs.py:929
     3647#: lib\pwiki\SearchAndReplaceDialogs.py:1094
     3648#: lib\pwiki\SearchAndReplaceDialogs.py:1110
     3649#: lib\pwiki\SearchAndReplaceDialogs.py:1158
     3650#: lib\pwiki\SearchAndReplaceDialogs.py:1169
     3651#: lib\pwiki\SearchAndReplaceDialogs.py:1237
     3652#: lib\pwiki\SearchAndReplaceDialogs.py:1276
     3653#: lib\pwiki\SearchAndReplaceDialogs.py:1430
     3654#: lib\pwiki\SearchAndReplaceDialogs.py:2043
    36553655msgid "Error in regular expression"
    36563656msgstr ""
    36573657
    3658 #: lib\pwiki\SearchAndReplaceDialogs.py:741
    3659 #: lib\pwiki\SearchAndReplaceDialogs.py:1235
     3658#: lib\pwiki\SearchAndReplaceDialogs.py:737
     3659#: lib\pwiki\SearchAndReplaceDialogs.py:1232
    36603660msgid "%i replacements done"
    36613661msgstr ""
    36623662
    3663 #: lib\pwiki\SearchAndReplaceDialogs.py:742
    3664 #: lib\pwiki\SearchAndReplaceDialogs.py:1180
    3665 #: lib\pwiki\SearchAndReplaceDialogs.py:1236
     3663#: lib\pwiki\SearchAndReplaceDialogs.py:738
     3664#: lib\pwiki\SearchAndReplaceDialogs.py:1177
     3665#: lib\pwiki\SearchAndReplaceDialogs.py:1233
    36663666msgid "Replace All"
    36673667msgstr ""
    36683668
    3669 #: lib\pwiki\SearchAndReplaceDialogs.py:931
     3669#: lib\pwiki\SearchAndReplaceDialogs.py:928
    36703670msgid "Bad regular expression '%s':\n"
    36713671"%s"
    36723672msgstr ""
    36733673
    3674 #: lib\pwiki\SearchAndReplaceDialogs.py:1180
     3674#: lib\pwiki\SearchAndReplaceDialogs.py:1177
    36753675msgid "Replace all occurrences?"
    36763676msgstr ""
    36773677
    3678 #: lib\pwiki\SearchAndReplaceDialogs.py:1287
     3678#: lib\pwiki\SearchAndReplaceDialogs.py:1284
    36793679msgid "Choose search title"
    36803680msgstr ""
    36813681
    3682 #: lib\pwiki\SearchAndReplaceDialogs.py:1297
     3682#: lib\pwiki\SearchAndReplaceDialogs.py:1294
    36833683msgid "Do you want to overwrite existing search '%s'?"
    36843684msgstr ""
    36853685
    3686 #: lib\pwiki\SearchAndReplaceDialogs.py:1298
     3686#: lib\pwiki\SearchAndReplaceDialogs.py:1295
    36873687msgid "Overwrite search"
    36883688msgstr ""
    36893689
    3690 #: lib\pwiki\SearchAndReplaceDialogs.py:1313
     3690#: lib\pwiki\SearchAndReplaceDialogs.py:1310
    36913691msgid "Invalid search string, can't save as view"
    36923692msgstr ""
    36933693
    3694 #: lib\pwiki\SearchAndReplaceDialogs.py:1412
     3694#: lib\pwiki\SearchAndReplaceDialogs.py:1409
    36953695msgid "Do you want to delete %i search(es)?"
    36963696msgstr ""
    36973697
    3698 #: lib\pwiki\SearchAndReplaceDialogs.py:1413
     3698#: lib\pwiki\SearchAndReplaceDialogs.py:1410
    36993699msgid "Delete search"
    37003700msgstr ""
    37013701
    3702 #: lib\pwiki\SearchAndReplaceDialogs.py:1505
     3702#: lib\pwiki\SearchAndReplaceDialogs.py:1502
    37033703msgid "*Set page list*"
    37043704msgstr ""
    37053705
    3706 #: lib\pwiki\SearchAndReplaceDialogs.py:1789
     3706#: lib\pwiki\SearchAndReplaceDialogs.py:1786
    37073707msgid "<Search: %s>"
    37083708msgstr ""
    37093709
    3710 #: lib\pwiki\SearchAndReplaceDialogs.py:1839
     3710#: lib\pwiki\SearchAndReplaceDialogs.py:1836
    37113711msgid "Fast Search"
    37123712msgstr ""
    37133713
    3714 #: lib\pwiki\SearchAndReplaceDialogs.py:1866
     3714#: lib\pwiki\SearchAndReplaceDialogs.py:1863
    37153715msgid "As Tab"
    37163716msgstr ""
    37173717
    3718 #: lib\pwiki\SearchAndReplaceDialogs.py:1906
     3718#: lib\pwiki\SearchAndReplaceDialogs.py:1903
    37193719msgid "Search: %s"
    37203720msgstr ""
    37213721
    3722 #: lib\pwiki\SearchAndReplaceDialogs.py:2089 lib\pwiki\WikiHtmlView.py:625
     3722#: lib\pwiki\SearchAndReplaceDialogs.py:2086 lib\pwiki\WikiHtmlView.py:625
    37233723msgid "Activate"
    37243724msgstr ""
    37253725
    3726 #: lib\pwiki\SearchAndReplaceDialogs.py:2091 lib\pwiki\WikiHtmlView.py:627
     3726#: lib\pwiki\SearchAndReplaceDialogs.py:2088 lib\pwiki\WikiHtmlView.py:627
    37273727msgid "Activate New Tab Backgrd."
    37283728msgstr ""
  • branches/mbutscher/work/WikidPad.xrc

    r190 r192  
    7373          <orient>wxHORIZONTAL</orient>
    7474          <object class="sizeritem">
    75             <object class="wxListBox" name="lbPages">
    76               <content/>
     75            <object class="wxBoxSizer">
     76              <orient>wxVERTICAL</orient>
     77              <object class="sizeritem">
     78                <object class="wxStaticText">
     79                  <label>Options page:</label>
     80                </object>
     81                <flag>wxALL|wxEXPAND|wxALIGN_CENTRE_VERTICAL</flag>
     82                <border>5</border>
     83              </object>
     84              <object class="sizeritem">
     85                <object class="wxListBox" name="lbPages">
     86                  <content/>
     87                </object>
     88                <option>1</option>
     89                <flag>wxALL|wxEXPAND|wxALIGN_CENTRE_VERTICAL</flag>
     90                <border>5</border>
     91              </object>
    7792            </object>
    7893            <option>1</option>
    79             <flag>wxALL|wxEXPAND|wxALIGN_CENTRE_VERTICAL</flag>
    80             <border>5</border>
     94            <flag>wxEXPAND</flag>
    8195          </object>
    8296          <object class="sizeritem">
     
    469483        <option>0</option>
    470484        <flag>wxTOP|wxLEFT|wxEXPAND|wxALIGN_CENTRE_VERTICAL</flag>
     485      </object>
     486      <object class="sizeritem">
     487        <object class="wxCheckBox" name="cbScriptSearchReverse">
     488          <label>Reverse script search order (global imports first)</label>
     489        </object>
     490        <option>0</option>
     491        <flag>wxALL|wxEXPAND|wxALIGN_CENTRE_VERTICAL</flag>
     492        <border>5</border>
    471493      </object>
    472494    </object>
     
    22012223          <label>Auto-show log window</label>
    22022224          <style>wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER</style>
     2225        </object>
     2226        <option>0</option>
     2227        <flag>wxALL|wxEXPAND|wxALIGN_CENTRE_VERTICAL</flag>
     2228        <border>5</border>
     2229      </object>
     2230      <object class="sizeritem">
     2231        <object class="wxCheckBox" name="cbWikiPageFilesAsciiOnly">
     2232          <label>Page file names ASCII only</label>
     2233        </object>
     2234        <option>0</option>
     2235        <flag>wxALL|wxEXPAND|wxALIGN_CENTRE_VERTICAL</flag>
     2236        <border>5</border>
     2237      </object>
     2238      <object class="sizeritem">
     2239        <object class="wxCheckBox" name="cbWikiPageFilesGracefulOutsideAddAndRemove">
     2240          <label>Graceful handling of missing page files</label>
    22032241        </object>
    22042242        <option>0</option>
  • branches/mbutscher/work/WikidPadHelp/WikidPadHelp.wiki

    r188 r192  
    1717wikipagetitle_fromlinktitle = True
    1818first_wiki_word = WikidPadHelp
     19wikipagefiles_gracefuloutsideaddandremove = True
    1920tree_expandednodes_rememberduration = 1
    2021tree_last_root_wiki_word = WikidPadHelp
     
    2526filestorage_identity_moddateisenough = False
    2627wiki_database_type = original_gadfly
     28wikipagefiles_asciionly = True
    2729export_default_dir =
    2830
  • branches/mbutscher/work/WikidPadHelp/data/ChangeLog.wiki

    r190 r192  
    11++ Change Log
     2
     3
     4Apr. 28, 2009 (2.0beta03)
     5
     6    * Option to reverse search order for scripts (global imports
     7      first). See [InlinePythonEval#+++ Security concerns]
     8    * Wiki-bound option to create wiki page files with ASCII-only
     9      names (does not apply to Compact Sqlite DB backend).
     10    * This should also fix a problem with Windows binary installer
     11      and WikidPad help wiki on non-western Windows versions.
     12      See [OptionsDialog#*Page file names ASCII only*]
     13    * Wiki-bound option to handle missing or externally inserted
     14      page files gracefully (does not apply to Compact Sqlite DB
     15      backend).
     16      See [OptionsDialog#*Graceful handling of missing page files*]
     17    * New insertion "iconimage" to insert an icon into an HTML page.
     18      See [Insertions#*iconimage*]
     19    * Preview shows link target in the status bar when hovering
     20      with mouse over it like browsers do
     21    * Menu item "Select All" in "Edit" menu (for completeness)
     22
     23    * Bug fixed: Some errors weren't recorded in error log
     24    * Bug fixed: Tree scrolled to wrong initial position on startup
     25    * Bug fixed: Windows: Spell check addon did not work due to
     26      wrong DLL find mechanism
     27    * Bug fixed: LossyWikiCloseDeniedException wasn't caught and
     28      polluted error log
     29    * Bug fixed: Search and replace dialog for page cleared
     30      "Search" text field when "Find next" was pressed
     31    * Bug fixed: Wiki-wide search dialog did not focus search
     32      text field when initially shown
     33    * Bug fixed: Pollution of error log if moving mouse over
     34      incremental search field
     35    * Bug fixed: stdDialog() of doc page presenter did not return
     36      a value (needed for some plugins)
     37
    238
    339
  • branches/mbutscher/work/WikidPadHelp/data/InlinePythonEval.wiki

    r182 r192  
    2020      but "global.import_scripts" does not
    2121    * Allow everything
     22
     23
     24When pressing Ctrl-1 to Ctrl-6 WikidPad searches for a script normally in the following order:
     25
     26    * Current page
     27    * Pages imported by current page with attribute "import_scripts"
     28    * Page imported somewhere with attribute "global.import_scripts"
     29
     30The latter two are only searched if security settings allow it.
     31The order can be reversed by checking option "Reverse script search order (global imports first)" on options page "Security".
     32
     33
     34
    2235
    2336
  • branches/mbutscher/work/WikidPadHelp/data/Insertions.wiki

    r188 r192  
    5858      the lines to go to the actual headings. The value of this
    5959      insertion must be empty.
     60    * *iconimage* shows the icon whose name is given as value.
     61      You can use menu "Format"->"Icon Name" to find the name of
     62      an existing icon.
    6063    * *eval* Evaluate the given Python expression and handle its
    6164      result as if it replaces the insertion. You must switch on
     
    6366      "Security" options page to make it work.
    6467    * *self* Shows the name of the current page.
    65      
     68
    6669
    6770For insertion tags which produce lists of wiki links (all but the "page" and "eval" insertion), you can also have the appendix "columns 123" where 123 stands for the number of columns the list should have. By default, there is only one column.
  • branches/mbutscher/work/WikidPadHelp/data/OptionsDialog.wiki

    r190 r192  
    8686
    8787*Script security*
    88 Set the security level for script execution, see [InlinePythonEval#+++ Security concerns] .
     88Set the security level for script execution, see [InlinePythonEval#+++ Security concerns].
     89
     90*Reverse script search order (global imports first)*
     91If checked, the order for searching of executable scripts is reversed, global imports are searched first (if allowed by the security setting above). See [InlinePythonEval#+++ Security concerns].
    8992
    9093
     
    366369
    367370*First word at startup*
    368 Wiki word which should be shown as first one each time the wiki is opened. If the field is empty, the last words when the wiki was closed is shown on opening.
     371Wiki word which should be shown as first one each time the wiki is opened. If the field is empty, the last words when the wiki was closed are shown on opening.
    369372
    370373*Default export dir.*
     
    391394If the check-box is gray, the application-bound setting (see above) is used, otherwise this wiki-bound setting overrides it.
    392395
     396*Page file names ASCII only*
     397If set, all filenames of newly created pages only contain ASCII-characters (no umlauts, accented characters etc.). Already created files are not renmed even if the file content is modified afterwards.
     398
     399This option does not apply to Compact Sqlite DB backend because it does not have separate page files.
     400
     401*Graceful handling of missing page files*
     402If a page file is deleted or inserted into the "data" directory externally tries to update the core database if it encounters this change.
     403
     404If not set, missing files which are listed in the core database issue an error and newly added files are ignored.
     405
     406This option does not apply to Compact Sqlite DB backend because it does not have separate page files.
     407
    393408*Wiki icon*
    394409Set here the name of icon to use in the system tray instead of the default icon. If the field is empty the default icon is used. The icon of the main window is not influenced by this setting (because it does not work).
  • branches/mbutscher/work/extensions/KeyBindings.py

    r166 r192  
    4646CopyToScratchPad="Ctrl-Alt-C"
    4747Paste="Ctrl-V"
     48SelectAll="Ctrl-A"
    4849Undo="Ctrl-Z"
    4950Redo="Ctrl-Y"
  • branches/mbutscher/work/extensions/wikidPadParser/WikidPadParser.py

    r188 r192  
    388388
    389389newLineLineBreak = newLine
    390 newLineLineBreak = newLineLineBreak.setResultsNameNoCopy("lineBreak")\
     390newLineLineBreak = newLineLineBreak.setResultsName("lineBreak")\
    391391        .setParseStartAction(preActNewLineLineBreak)\
    392392        .setParseAction(actionResetIndent)
     
    394394
    395395newLineWhitespace = newLine
    396 newLineWhitespace = newLineWhitespace.setResultsNameNoCopy("whitespace")\
     396newLineWhitespace = newLineWhitespace.setResultsName("whitespace")\
    397397        .setParseStartAction(preActNewLineWhitespace)
    398398
     
    12831283        thread.
    12841284        """
    1285        
     1285
     1286        if len(content) == 0:
     1287            return buildSyntaxNode([], 0, "text")
     1288
    12861289        if formatDetails.noFormat:
    12871290            return buildSyntaxNode([buildSyntaxNode(content, 0, "plainText")],
  • branches/mbutscher/work/lib/pwiki/AdditionalDialogs.py

    r190 r192  
    14101410            etypeProfile = Serialization.serFromXmlUnicode(xmlNode,
    14111411                    u"exportTypeName")
    1412            
     1412
    14131413            for sel, (ob, etype, desc, panel) in enumerate(self.exporterList):
    14141414                if etype == etypeProfile:
     
    14221422            addOptXml = Serialization.findXmlElementFlat(xmlNode,
    14231423                    u"additionalOptions")
    1424    
     1424
    14251425            addOptVersion = int(addOptXml.getAttribute(u"version"))
    1426    
     1426
    14271427            if addOptVersion != ob.getAddOptVersion():
    14281428                self.mainControl.displayErrorMessage(
     
    14321432                        (etypeProfile, addOptVersion, ob.getAddOptVersion()))
    14331433                return False
    1434    
     1434
    14351435            if addOptXml.getAttribute(u"type") != u"simpleTuple":
    14361436                self.mainControl.displayErrorMessage(
  • branches/mbutscher/work/lib/pwiki/Configuration.py

    r190 r192  
    586586            # import_scripts property? 0: No scripts at all; 1: No import_scripts;
    587587            # 2: allow local import_scripts; 3: allow also global.import_scripts
     588    ("main", "script_search_reverse"): "False", # Normally when searching for a script first the local page
     589            # is searched, then local import_scripts, then global.import_scripts. If this is set to
     590            # True the search order is reversed
     591
    588592
    589593    # HTML options
     
    748752            # if it is not a child of it
    749753
    750 
    751754    ("main", "further_wiki_words"): u"", # Semicolon separated list of further wiki words to show in addit. tabs
    752755            # after last wiki word
     
    762765    ("main", "wiki_readOnly"): "False",   # Should wiki be read only?
    763766
    764     ("main", "log_window_autoshow"): "Gray", # Automatically show log window if messages added?
     767    ("main", "log_window_autoshow"): "Gray", # Automatically show log window if messages added? "Gray" means to look at
     768            # global configuration for same setting
     769
     770    ("main", "wikiPageFiles_asciiOnly"): "False", # Use only ASCII characters in filenames of wiki page files.
     771    ("main", "wikiPageFiles_gracefulOutsideAddAndRemove"): "True",   # Handle missing wiki page files gracefully and try
     772            # to find existing files even if they are not in database.
    765773
    766774    ("main", "headingsAsAliases_depth"): "0",  # Maximum heading depth for which aliases should be generated for
     
    789797
    790798
     799
     800# If the fallthrough value is set in the wiki-bound config. then
     801# the global config. value is used instead
    791802WIKIFALLTHROUGH ={
    792803    ("main", "log_window_autoshow"): "Gray"
  • branches/mbutscher/work/lib/pwiki/DocPagePresenter.py

    r178 r192  
    322322        Calls same function from PersonalWikiFrame.
    323323        """
    324         self.mainControl.stdDialog(dlgtype, title, message, additional)
     324        return self.mainControl.stdDialog(dlgtype, title, message, additional)
    325325
    326326
  • branches/mbutscher/work/lib/pwiki/DocStructureCtrl.py

    r190 r192  
    4444        ), wx.GetApp().getMiscEvent(), self)
    4545
    46         self.__sinkMainFrame = wxKeyFunctionSink((
    47                 ("constructed main window", self.onConstructedMainWindow),
    48         ), self.mainControl.getMiscEvent(), self)
     46        if not self.mainControl.isMainWindowConstructed():
     47            # Install event handler to wait for construction
     48            self.__sinkMainFrame = wxKeyFunctionSink((
     49                    ("constructed main window", self.onConstructedMainWindow),
     50            ), self.mainControl.getMiscEvent(), self)
     51        else:
     52            self.onConstructedMainWindow(None)
    4953
    5054        currPres = self.mainControl.getCurrentDocPagePresenter()
  • branches/mbutscher/work/lib/pwiki/EnchantDriver.py

    r167 r192  
    176176
    177177
     178
     179if os.name == "nt":
     180    ctypes_find_library = find_library
     181
     182    def find_library(name):
     183#         if name in ('c', 'm'):
     184#             return find_msvcrt()
     185        # See MSDN for the REAL search order.
     186        for directory in [os.path.dirname(os.path.abspath(sys.argv[0]))] + os.environ['PATH'].split(os.pathsep):
     187            fname = os.path.join(directory, name)
     188            if os.path.exists(fname):
     189                return fname
     190            if fname.lower().endswith(".dll"):
     191                continue
     192            fname = fname + ".dll"
     193            if os.path.exists(fname):
     194                return fname
     195        return None
     196
     197
     198
     199
    178200#  -------------------- From _enchant module --------------------
    179201
  • branches/mbutscher/work/lib/pwiki/Exporters.py

    r190 r192  
    304304                # of the current word.
    305305        self.tempFileSet = None
     306        self.copiedTempFileCache = None  # Dictionary {<original path>: <target URL>}
    306307        self.convertFilename = removeBracketsFilename   # lambda s: mbcsEnc(s, "replace")[0]
    307308       
     
    425426
    426427       
    427        
     428
     429    def setJobData(self, wikiDocument, wordList, exportType, exportDest,
     430            compatFilenames, addOpt, progressHandler):
     431        """
     432        Set all information necessary to run export operation.
     433        """
     434
     435        self.setWikiDocument(wikiDocument)
     436
     437        self.wordList = []
     438        for w in wordList:
     439            if self.wikiDocument.isDefinedWikiLink(w):
     440                self.wordList.append(w)
     441
     442        if len(self.wordList) == 0:
     443            return False
     444
     445#         self.wordList = wordList
     446        self.exportType = exportType
     447        self.exportDest = exportDest
     448        self.addOpt = addOpt
     449        self.progressHandler = progressHandler
     450        self.compatFilenames = compatFilenames
     451
     452        if compatFilenames:
     453            self.convertFilename = removeBracketsToCompFilename
     454        else:
     455            self.convertFilename = removeBracketsFilename    # lambda s: mbcsEnc(s, "replace")[0]
     456           
     457        self.referencedStorageFiles = None
     458       
     459        return True
     460
     461
    428462
    429463    def export(self, wikiDocument, wordList, exportType, exportDest,
     
    445479#             compatFilenames, addopt))
    446480
    447         self.setWikiDocument(wikiDocument)
    448 
    449         self.wordList = []
    450         for w in wordList:
    451             if self.wikiDocument.isDefinedWikiLink(w):
    452                 self.wordList.append(w)
    453 
    454         if len(self.wordList) == 0:
     481        if not self.setJobData(wikiDocument, wordList, exportType, exportDest,
     482                compatFilenames, addOpt, progressHandler):
    455483            return
    456 
    457 #         self.wordList = wordList
    458         self.exportType = exportType
    459         self.exportDest = exportDest
    460         self.addOpt = addOpt
    461         self.progressHandler = progressHandler
    462         self.compatFilenames = compatFilenames
    463 
    464         if compatFilenames:
    465             self.convertFilename = removeBracketsToCompFilename
    466         else:
    467             self.convertFilename = removeBracketsFilename    # lambda s: mbcsEnc(s, "replace")[0]
    468            
    469         self.referencedStorageFiles = None
    470484
    471485        if exportType in (u"html_single", u"html_multi"):
     
    494508
    495509        # Other supported types: html_previewWX, html_previewIE, html_previewMOZ
     510        # are not handled in this function
    496511
    497512        wx.GetApp().getInsertionPluginManager().taskEnd()
     
    515530            self.tempFileSet.reset()
    516531            self.tempFileSet = None
     532            self.copiedTempFileCache = None
    517533
    518534
     
    547563        self.tempFileSet.reset()
    548564        self.tempFileSet = None
     565        self.copiedTempFileCache = None
    549566
    550567
     
    12041221        self.optsStack = StackedCopyDict()
    12051222        self.insertionVisitStack = []
     1223        self.copiedTempFileCache = {}
     1224
    12061225        self.outFlagEatPostBreak = False
    12071226        self.outFlagPostBreakEaten = False
     
    13631382            if self.asIntHtmlPreview:
    13641383                # It is already indented, so additional indents will not
    1365                 # produce blank lines which must be eaten
    1366                 self.outAppend(tag)
     1384                # produce blank lines which must be eaten  (?)
     1385                self.outAppend(tag, eatPreBreak=True)
    13671386            else:
    13681387                self.outEatBreaks(tag)
     
    15231542                    htmlContent = u"\n<pre>\n" + \
    15241543                            escapeHtmlNoBreaks(s.getvalue()) + u"\n</pre>\n"
     1544        elif key == u"iconimage":
     1545            imgName = astNode.value
     1546            icPath = wx.GetApp().getIconCache().lookupIconPath(imgName)
     1547            if icPath is None:
     1548                htmlContent = _(u"<pre>[Icon '%s' not found]</pre>" % imgName)
     1549            else:
     1550                url = self.copiedTempFileCache.get(icPath)
     1551                if url is None:
     1552                    tfs = self.getTempFileSet()
     1553                    # TODO Take suffix from icPath
     1554                    dstFullPath = tfs.createTempFile("", ".gif", relativeTo="")
     1555                    pythonUrl = (self.exportType != "html_previewWX")
     1556                    url = tfs.getRelativeUrl(None, dstFullPath, pythonUrl=pythonUrl)
     1557
     1558                    OsAbstract.copyFile(icPath, dstFullPath)
     1559                    self.copiedTempFileCache[icPath] = url
     1560               
     1561                htmlContent = u'<img src="%s" />' % url
    15251562        else:
    15261563            # Call external plugins
     
    17561793
    17571794            elif tname == "bullet":
     1795#                 print "--bullet1", repr(self.result[-1])
    17581796                self.outAppend(u"\n<li />", eatPreBreak=True)
    17591797            elif tname == "number":
  • branches/mbutscher/work/lib/pwiki/OptionsDialog.py

    r190 r192  
    387387#             ("tempFiles_inWikiDir", "cbTempFilesInWikiDir", "b"),
    388388            ("script_security_level", "chScriptSecurityLevel", "seli"),
     389            ("script_search_reverse", "cbScriptSearchReverse", "b"),
    389390
    390391
     
    556557
    557558            ("option/wiki/log_window_autoshow", "cbLogWindowAutoShowWiki", "b3"),
     559
     560            # The following two need special handling on dialog construction
     561            ("wikiPageFiles_asciiOnly", "cbWikiPageFilesAsciiOnly", "b"),
     562            ("wikiPageFiles_gracefulOutsideAddAndRemove",
     563                    "cbWikiPageFilesGracefulOutsideAddAndRemove", "b"),
    558564
    559565            ("wiki_icon", "tfWikiIcon", "t"),
     
    772778            self.ctrls.cbWikiReadOnly.SetValue(
    773779                    wikiDocument.getWriteAccessDeniedByConfig())
    774        
     780
     781            fppCap = wikiDocument.getWikiData().checkCapability("filePerPage")
     782           
     783            self.ctrls.cbWikiPageFilesAsciiOnly.Enable(fppCap is not None)
     784            self.ctrls.cbWikiPageFilesGracefulOutsideAddAndRemove.Enable(
     785                    fppCap is not None)
     786
    775787        self.OnEditorImagePasteFileTypeChoice(None)
    776788
     789
     790        # Now show the right panel
    777791        self.activePageIndex = -1
    778792        for panel in self.panelList:
  • branches/mbutscher/work/lib/pwiki/PersonalWikiFrame.py

    r190 r192  
    157157
    158158        self.sleepMode = False  # Is program in low resource sleep mode?
     159        self.mainWindowConstructed = False
    159160
    160161#         if not globalConfigDir or not exists(globalConfigDir):
     
    183184""", True)
    184185        self.configuration = wx.GetApp().createCombinedConfiguration()
    185        
     186
    186187        # Listen to application events
    187188        wx.GetApp().getMiscEvent().addListener(self)
     
    228229        self.currentWikiDocumentProxyEvent.addListener(self)
    229230
     231        self.configuration.setGlobalConfig(wx.GetApp().getGlobalConfig())
     232
     233        # State here: Global configuration available
     234
    230235        # setup plugin manager and hooks API
    231236        dirs = ( join(self.globalConfigSubDir, u'user_extensions'),
     
    251256        self.propertyChecker = PropertyHandling.PropertyChecker(self)
    252257
    253         self.configuration.setGlobalConfig(wx.GetApp().getGlobalConfig())
     258#         self.configuration.setGlobalConfig(wx.GetApp().getGlobalConfig())
     259
     260        # State here: Plugins loaded
    254261
    255262        # trigger hook
     
    304311                "timeView_position", 0)
    305312
    306         # this will keep track of the last font used in the editor
    307         self.lastEditorFont = None
    308 
    309         # should WikiWords be enabled or not for the current wiki
    310         self.wikiWordsEnabled = True
    311 
    312313        # if a wiki to open wasn't passed in use the last_wiki from the global config
    313314        wikiToOpen = cmdLineAction.wikiToOpen
     
    322323
    323324        # Minimize on tray?
    324         ## self.showOnTray = self.globalConfig.getboolean("main", "showontray")
    325 
    326325        self.tbIcon = None
    327326        self.setShowOnTray()
     
    334333        if windowmode & 2:
    335334            self.Iconize(True)
    336            
     335
    337336        # Set app-bound hot key
    338337        self.hotKeyDummyWindow = None
    339338        self._refreshHotKeys()
     339
     340        self.windowLayouter.layout()
     341       
     342        # State here: GUI construction finished, but frame is hidden yet
    340343
    341344        # if a wiki to open is set, open it
     
    364367
    365368        # Inform that idle handlers and window-specific threads can now be started
     369        self.mainWindowConstructed = True
    366370        self.fireMiscEventKeys(("constructed main window",))
    367371
     
    420424    def getMainAreaPanel(self):
    421425        return self.mainAreaPanel
     426       
     427    def isMainWindowConstructed(self):
     428        return self.mainWindowConstructed
    422429
    423430    def getCurrentDocPagePresenter(self):
     
    892899        if not history:
    893900            return
    894        
     901
    895902        self.wikiHistory = history.split(u";")
    896        
     903
    897904        maxLen = self.configuration.getint(
    898905                "main", "recentWikisList_length", 5)
     
    11671174                "tb_paste", menuID=GUI_ID.CMD_CLIPBOARD_PASTE,
    11681175                updatefct=(self.OnUpdateDisReadOnlyPage, self.OnUpdateDisNotTextedit))
     1176
     1177        self.addMenuItem(editMenu, _(u'Select &All') + u'\t' + self.keyBindings.SelectAll,
     1178                _(u'Select All'), self._OnRoundtripEvent,
     1179                 menuID=GUI_ID.CMD_SELECT_ALL)
    11691180
    11701181        editMenu.AppendSeparator()
     
    52155226            self.Iconize(True)
    52165227        else:
     5228            try:
    52175229#             tracer.runctx('self._prepareExitWiki()', globals(), locals())
    5218             self._prepareExitWiki()
    5219             self.Destroy()
    5220             evt.Skip()
     5230                self._prepareExitWiki()
     5231                self.Destroy()
     5232                evt.Skip()
     5233            except LossyWikiCloseDeniedException:
     5234                pass
    52215235
    52225236
  • branches/mbutscher/work/lib/pwiki/Printing.py

    r188 r192  
    55
    66
    7 import wx, wx.xrc
     7import wx, wx.xrc, wx.html
    88
    99from wxHelper import *
     
    5050        # Fixes focus bug under Linux
    5151        self.SetFocus()
    52        
     52
    5353        wx.EVT_CHOICE(self, GUI_ID.chSelectedSet, self.OnChSelectedSet)
    5454
     
    6464        if sel == -1:
    6565            sel = self.printer.selectionSet
    66            
    67         self.printer.setStdOptions(sel, self.plainTextFontDesc,
     66
     67        self.printer.setStdOptions(sel, self.ctrls.chExportTo.GetSelection(),
     68                self.plainTextFontDesc,
    6869                self.ctrls.tfWikiPageSeparator.GetValue())
    6970
     
    128129
    129130        self.selectionSet = 0
     131        self.printType = 0  # 0: Plain text; 1: HTML
    130132        self.listPagesOperation = SearchReplaceOperation()
    131133
     
    150152            self.psddata.SetMarginTopLeft(wx.Point(margins[0], margins[1]))
    151153            self.psddata.SetMarginBottomRight(wx.Point(margins[2], margins[3]))
    152        
    153 
    154     def setStdOptions(self, selectionSet, plainTextFontDesc, wpSeparator):
     154
     155
     156    def setStdOptions(self, selectionSet, printType, plainTextFontDesc,
     157            wpSeparator):
    155158        self.selectionSet = selectionSet
     159        self.printType = printType
    156160        self.plainTextFontDesc = plainTextFontDesc
    157161        self.pWiki.configuration.set("main", "print_plaintext_font",
     
    231235
    232236    def doPreview(self):
    233         printObj = PlainTextPrint()
    234         printObj.setContext(self.pWiki, self, self.pWiki.getWikiDocument(),
    235                 self.buildWordList(), "plain_text", None, None)
     237        if self.printType == 1:
     238            printObj = HtmlPrint()
     239            printObj.setContext(self.pWiki, self, self.pWiki.getWikiDocument(),
     240                    self.buildWordList(), "html_simple", None, None)
     241        else: # self.printType == 0:
     242            printObj = PlainTextPrint()
     243            printObj.setContext(self.pWiki, self, self.pWiki.getWikiDocument(),
     244                    self.buildWordList(), "plain_text", None, None)
    236245
    237246        return printObj.doPreview()
     
    239248                   
    240249    def doPrint(self):
    241         printObj = PlainTextPrint()
    242         printObj.setContext(self.pWiki, self, self.pWiki.getWikiDocument(),
    243                 self.buildWordList(), "plain_text", None, None)
     250        if self.printType == 1:
     251            printObj = HtmlPrint()
     252            printObj.setContext(self.pWiki, self, self.pWiki.getWikiDocument(),
     253                    self.buildWordList(), "html_simple", None, None)
     254        else:
     255            printObj = PlainTextPrint()
     256            printObj.setContext(self.pWiki, self, self.pWiki.getWikiDocument(),
     257                    self.buildWordList(), "plain_text", None, None)
    244258
    245259        return printObj.doPrint()
     260
     261
     262
    246263
    247264
     
    297314        printout = PlainTextPrintout(text, self.printer)
    298315        printout2 = PlainTextPrintout(text, self.printer)
     316
    299317        preview = wx.PrintPreview(printout, printout2, pddata)
    300318
     
    306324        frame.SetSize(self.pWiki.GetSize())
    307325        frame.Show(True)
     326
     327
     328
    308329
    309330
     
    538559        return True
    539560
     561
     562
     563
     564
     565class HtmlPrint:
     566    def __init__(self):
     567        self.printOptions = None
     568        self.pWiki = None
     569
     570    def getPrintTypes(self):
     571        return (
     572            ("html_simple", u'HTML', None),
     573            )
     574
     575    def _buildText(self):
     576        def getTextFromWord(word):
     577            return self.wikiDocument.getWikiPage(word).getLiveText()
     578
     579        contents = map(getTextFromWord, self.wordList)
     580        # Ensure that each wiki word content ends with newline
     581        for i, c in enumerate(contents):
     582            if len(c) > 0 and c[-1] != "\n":
     583                contents[i] += "\n"
     584               
     585        try:
     586            separator = unescapeWithRe(self.pWiki.getConfig().get(
     587                    "main", "print_plaintext_wpseparator"))
     588        except:
     589            separator = u"\n\n\n\n"   # TODO Error message
     590       
     591        return separator.join(contents)  # TODO Make configurable
     592           
     593           
     594    def setContext(self, pWiki, printer, wikiDocument, wordList, printType, options,
     595            addopt):
     596        self.pWiki = pWiki
     597        self.wikiDocument = wikiDocument
     598        self.wordList = wordList
     599        self.printer = printer
     600
     601    def doPrint(self):
     602        text = self._buildText()
     603
     604        printout = HtmlPrintout(text, self.printer)   # !!!!!
     605        printer = wx.Printer(wx.PrintDialogData(self.printer.printData))
     606        return printer.Print(self.pWiki, printout, True)
     607
     608
     609    def doPreview(self):
     610        text = self._buildText()
     611       
     612        pddata = wx.PrintDialogData(self.printer.printData)
     613        printout = HtmlPrintout()
     614        printout2 = HtmlPrintout()
     615
     616        preview = wx.PrintPreview(printout, printout2, pddata)
     617
     618        frame = wx.PreviewFrame(preview, self.pWiki, _(u"Print Preview"),
     619                style=wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT)
     620
     621        frame.Initialize()
     622        frame.SetPosition(self.pWiki.GetPosition())
     623        frame.SetSize(self.pWiki.GetSize())
     624        frame.Show(True)
     625
     626
     627class HtmlPrintout(wx.html.HtmlPrintout):
     628    def __init__(self):
     629        wx.html.HtmlPrintout.__init__(self)
     630       
     631        self.exporterInstance = Exporters.HtmlExporter(
     632                self.presenter.getMainControl())
     633       
     634        self.exporterInstance.exportType = u"html_previewWX"
     635        self.exporterInstance.styleSheet = u""
     636        self.exporterInstance.tempFileSet = TempFileSet()
     637       
     638       
     639
     640#     def _updateTempFilePrefPath(self):
     641#         wikiDocument = self.presenter.getWikiDocument()
     642#
     643#         if wikiDocument is not None:
     644#             self.exporterInstance.tempFileSet.setPreferredPath(
     645#                     wikiDocument.getWikiTempDir())
     646#         else:
     647#             self.exporterInstance.tempFileSet.setPreferredPath(None)
     648
     649       
     650#         self.SetHtmlText(u"ab<br />\n" * 5000)
     651
     652
     653
     654
  • branches/mbutscher/work/lib/pwiki/SearchAndReplaceDialogs.py

    r190 r192  
    55from MiscEvent import MiscEventSourceMixin, KeyFunctionSink
    66import Consts
     7from WikiExceptions import *
     8
    79from wxHelper import *
    810
     
    536538                        info.occPos[0], info.occPos[1])
    537539           
    538             # Don't change focus when activating new tab in background
    539 #             # Works in fast search popup only if called twice
    540 #             self.pWiki.getActiveEditor().SetFocus()
    541 #             self.pWiki.getActiveEditor().SetFocus()
    542 
    543 
    544 
    545 
    546 class SearchPageDialog(wx.Dialog):   # TODO
     540
     541
     542
     543
     544class SearchPageDialog(wx.Dialog):
    547545    def __init__(self, pWiki, ID, title="",
    548546                 pos=wx.DefaultPosition, size=wx.DefaultSize,
     
    638636#         self.ctrls.cbSearch.Clear()
    639637#         self.ctrls.cbSearch.AppendItems([tpl[0] for tpl in hist])
    640         self._refreshSearchHistoryCombo()
    641         text = self.ctrls.cbSearch.GetValue()
    642         self.ctrls.cbSearch.SetValue(text)
     638
     639        self.ctrls.cbSearch.Freeze()
     640        try:
     641            text = self.ctrls.cbSearch.GetValue()
     642            self._refreshSearchHistoryCombo()
     643            self.ctrls.cbSearch.SetValue(text)
     644        finally:
     645            self.ctrls.cbSearch.Thaw()
     646
    643647
    644648    def _refreshSearchHistoryCombo(self):
     
    691695
    692696    def OnFindNext(self, evt):
     697        if guiToUni(self.ctrls.cbSearch.GetValue()) == u"":
     698            return
     699
    693700        sarOp = self._buildSearchOperation()
    694701        sarOp.replaceOp = False
     
    811818        # Fixes focus bug under Linux
    812819        self.SetFocus()
     820        self.ctrls.cbSearch.SetFocus()
    813821
    814822        # Events from text search tab
     
    10971105            self.displayErrorMessage(_(u'Error in regular expression'),
    10981106                    _(unicode(e)))
     1107        except DbReadAccessError, e:
     1108            self.displayErrorMessage(_(u'Error. Maybe wiki rebuild is needed'),
     1109                    _(unicode(e)))
     1110            return
     1111
    10991112
    11001113    def OnListRefreshNeeded(self, evt):
     
    11121125            except re.error, e:
    11131126                self.displayErrorMessage(_(u'Error in regular expression'),
     1127                        _(unicode(e)))
     1128                return
     1129            except DbReadAccessError, e:
     1130                self.displayErrorMessage(_(u'Error. Maybe wiki rebuild is needed'),
    11141131                        _(unicode(e)))
    11151132                return
     
    12401257            self.displayErrorMessage(_(u'Error in regular expression'),
    12411258                    _(unicode(e)))
     1259        except DbReadAccessError, e:
     1260            self.displayErrorMessage(_(u'Error. Maybe wiki rebuild is needed'),
     1261                    _(unicode(e)))
    12421262
    12431263
     
    14321452            except re.error, e:
    14331453                self.displayErrorMessage(_(u'Error in regular expression'),
     1454                        _(unicode(e)))
     1455            except DbReadAccessError, e:
     1456                self.displayErrorMessage(_(u'Error. Maybe wiki rebuild is needed'),
    14341457                        _(unicode(e)))
    14351458
     
    20462069            self.displayErrorMessage(_(u'Error in regular expression'),
    20472070                    _(unicode(e)))
     2071        except DbReadAccessError, e:
     2072            self.displayErrorMessage(_(u'Error. Maybe wiki rebuild is needed'),
     2073                    _(unicode(e)))
    20482074
    20492075
  • branches/mbutscher/work/lib/pwiki/SpellChecker.py

    r188 r192  
    1111except (AttributeError, ImportError):
    1212    Dict = None
    13 #    traceback.print_exc()
     13    # traceback.print_exc()
    1414
    1515
     
    110110            self.spellChkAddedLocal = None
    111111            self.localPwlPage = None
    112            
    113            
     112
     113
    114114    def _showInfo(self, msg):
    115115        """
     
    322322        """
    323323        Add word globally (application-wide)
    324         """ 
     324        """
     325        if self.spellChkAddedGlobal is None:
     326            return  # TODO When does this happen?
    325327        self.spellChkAddedGlobal.add(self.currentCheckedWord)
    326328        words = list(self.spellChkAddedGlobal)
     
    335337        Add word locally (wiki-wide)
    336338        """
     339        if self.spellChkAddedLocal is None:
     340            return  # TODO When does this happen?
     341
    337342        self.spellChkAddedLocal.add(self.currentCheckedWord)
    338343        words = list(self.spellChkAddedLocal)
  • branches/mbutscher/work/lib/pwiki/StringOps.py

    r190 r192  
    55creating diff information for plain byte sequences
    66"""
    7 
    87
    98
     
    13301329#     
    13311330#     return result
    1332 
    13331331
    13341332
  • branches/mbutscher/work/lib/pwiki/WikiHtmlView.py

    r188 r192  
    1212from MiscEvent import KeyFunctionSink
    1313
    14 from StringOps import uniToGui, pathnameFromUrl
     14from StringOps import uniToGui, pathnameFromUrl, flexibleUrlUnquote
    1515from Configuration import isWindows, MIDDLE_MOUSE_CONFIG_TO_TABMODE, isOSX
    1616
     
    170170
    171171        wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_COPY, self.OnClipboardCopy)
     172        wx.EVT_MENU(self, GUI_ID.CMD_SELECT_ALL, lambda evt: self.SelectAll())
    172173        wx.EVT_MENU(self, GUI_ID.CMD_ZOOM_IN, lambda evt: self.addZoom(1))
    173174        wx.EVT_MENU(self, GUI_ID.CMD_ZOOM_OUT, lambda evt: self.addZoom(-1))
     
    580581            cell = irep.FindCellByPos(pos.x, pos.y)
    581582        callTip = u""
     583        status = u""
    582584
    583585        if cell is not None:
     
    593595                    try:
    594596                        wikiWord, anchor = href[22:].split(u"#", 1)
     597                        anchor = flexibleUrlUnquote(anchor)
    595598                    except ValueError:
    596599                        wikiWord = href[22:]
    597600                        anchor = None
    598601
     602                    wikiWord = flexibleUrlUnquote(wikiWord)
     603                   
    599604                    wikiDocument = self.presenter.getWikiDocument()
    600605                    if wikiDocument is None:
     
    608613                        if len(propList) > 0:
    609614                            callTip = propList[-1][2]
     615                       
     616                        status = _(u"Link to page: %s") % wikiWord
     617                else:
     618                    status = href
     619
     620        self.presenter.getMainControl().statusBar.SetStatusText(
     621                        uniToGui(status), 0)
    610622
    611623        self.SetToolTipString(callTip)
  • branches/mbutscher/work/lib/pwiki/WikiHtmlViewIE.py

    r178 r192  
    3636
    3737from StringOps import uniToGui, utf8Enc, utf8Dec, urlFromPathname, urlQuote, \
    38         pathnameFromUrl
     38        pathnameFromUrl, flexibleUrlUnquote
    3939
    4040import DocPages
     
    449449            Cancel[0] = True
    450450
     451
     452    def StatusTextChange(self, status):
     453        if self.visible:
     454            if self.drivingMoz:
     455                internaljumpPrefix = u"file://internaljump/wikipage/"
     456            else:
     457                internaljumpPrefix = u"internaljump:wikipage/"
     458
     459            if status.startswith(internaljumpPrefix):
     460                # First check for an anchor. In URLs, anchors are always
     461                # separated by '#' regardless which character is used
     462                # in the wiki syntax (normally '!')
     463                try:
     464                    wikiWord, anchor = status[len(internaljumpPrefix):].split(
     465                            u"#", 1)
     466                    anchor = flexibleUrlUnquote(anchor)
     467                except ValueError:
     468                    wikiWord = status[len(internaljumpPrefix):]
     469                    anchor = None
     470
     471                wikiWord = flexibleUrlUnquote(wikiWord)
     472
     473                wikiDocument = self.presenter.getWikiDocument()
     474                if wikiDocument is None:
     475                    return
     476                wikiWord = wikiDocument.getUnAliasedWikiWord(wikiWord)
     477
     478                if wikiWord is not None:
     479                    status = _(u"Link to page: %s") % wikiWord
     480
     481
     482            self.presenter.getMainControl().statusBar.SetStatusText(
     483                    uniToGui(status), 0)
    451484
    452485
  • branches/mbutscher/work/lib/pwiki/WikiTreeCtrl.py

    r190 r192  
    14001400    def onOptionsChanged(self, miscevt):
    14011401        config = self.pWiki.getConfig()
    1402        
     1402
    14031403        coltuple = htmlColorToRgbTuple(config.get("main", "tree_bg_color"))   
    1404        
     1404
    14051405        if coltuple is None:
    14061406            coltuple = (255, 255, 255)
    14071407
    14081408        self.SetBackgroundColour(wx.Colour(*coltuple))
     1409       
     1410#         self.SetDefaultScrollVisiblePos("middle")
     1411
    14091412        self.Refresh()
    14101413       
     
    18041807
    18051808                if doexpand:
    1806                     self.EnsureVisible(currentNode)                           
     1809                    self.EnsureVisible(currentNode)
    18071810                if selectNode:
    18081811                    self._unbindActivation()
  • branches/mbutscher/work/lib/pwiki/WikiTxtCtrl.py

    r190 r192  
    136136
    137137    def OnMouseAnyInput(self, evt):
    138         if evt.Button(wx.MOUSE_BTN_ANY) and self.closeDelay:
     138#         if evt.Button(wx.MOUSE_BTN_ANY) and self.closeDelay:
     139
     140        # Workaround for name clash in wx.MouseEvent.Button:
     141        if wx._core_.MouseEvent_Button(evt, wx.MOUSE_BTN_ANY) and self.closeDelay:
    139142            # If a mouse button was pressed/released, restart timer
    140143            self.closeTimer.Start(self.closeDelay, True)
     
    412415        ), wx.GetApp().getMiscEvent(), self)
    413416
    414         self.__sinkMainFrame = wxKeyFunctionSink((
    415                 ("constructed main window", self.onConstructedMainWindow),
    416         ), self.presenter.getMainControl().getMiscEvent(), self)
     417        if not self.presenter.getMainControl().isMainWindowConstructed():
     418            # Install event handler to wait for construction
     419            self.__sinkMainFrame = wxKeyFunctionSink((
     420                    ("constructed main window", self.onConstructedMainWindow),
     421            ), self.presenter.getMainControl().getMiscEvent(), self)
     422        else:
     423            self.onConstructedMainWindow(None)
    417424
    418425#         self.presenter.getMiscEvent().addListener(self.presenterListener)
     
    469476        wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_COPY, lambda evt: self.Copy())
    470477        wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_PASTE, lambda evt: self.Paste())
     478        wx.EVT_MENU(self, GUI_ID.CMD_SELECT_ALL, lambda evt: self.SelectAll())
     479
    471480        wx.EVT_MENU(self, GUI_ID.CMD_TEXT_DELETE, lambda evt: self.ReplaceSelection(""))
    472481        wx.EVT_MENU(self, GUI_ID.CMD_ZOOM_IN,
     
    19481957           
    19491958            pageAst = self.getPageAst()
    1950             scriptNodes = list(pageAst.iterDeepByName(SCRIPTFORMAT))
     1959            scriptNodeGroups = [list(pageAst.iterDeepByName(SCRIPTFORMAT))]
    19511960           
    19521961            # process script imports
    19531962            if securityLevel > 1: # Local import_scripts properties allowed
    19541963                if self.getLoadedDocPage().getProperties().has_key(
    1955                         "import_scripts"):
     1964                        u"import_scripts"):
    19561965                    scriptNames = self.getLoadedDocPage().getProperties()[
    1957                             "import_scripts"]
     1966                            u"import_scripts"]
    19581967                    for sn in scriptNames:
    19591968                        try:
     
    19611970                                    getWikiPage(sn)
    19621971                            pageAst = importPage.getLivePageAst()
    1963                             scriptNodes += list(
    1964                                     pageAst.iterDeepByName(SCRIPTFORMAT))
     1972                            scriptNodeGroups.append(list(
     1973                                    pageAst.iterDeepByName(SCRIPTFORMAT)))
    19651974                        except:
    19661975                            pass
     
    19681977            if securityLevel > 2: # global.import_scripts property also allowed
    19691978                globScriptName = self.presenter.getWikiDocument().getWikiData().\
    1970                         getGlobalProperties().get("global.import_scripts")
     1979                        getGlobalProperties().get(u"global.import_scripts")
    19711980
    19721981                if globScriptName is not None:
     
    19751984                                getWikiPage(globScriptName)
    19761985                        pageAst = importPage.getLivePageAst()
    1977                         scriptNodes += list(
    1978                                     pageAst.iterDeepByName(SCRIPTFORMAT))
     1986                        scriptNodeGroups.append(list(
     1987                                    pageAst.iterDeepByName(SCRIPTFORMAT)))
    19791988                    except:
    19801989                        pass
    1981 
     1990             
     1991            if self.presenter.getConfig().getboolean("main",
     1992                    "script_search_reverse", False):
     1993                scriptNodeGroups.reverse()
     1994
     1995            scriptNodes = reduce(lambda a, b: a + b, scriptNodeGroups)
     1996           
    19821997            for node in scriptNodes:
    19831998                script = node.findFlatByName("code").getString()
  • branches/mbutscher/work/lib/pwiki/customtreectrl.py

    r177 r192  
    160160import zlib
    161161import cStringIO
     162import traceback
     163
    162164
    163165# ----------------------------------------------------------------------------
     
    19081910        self._vistaselection = False       
    19091911
     1912        self._defaultScrollVisiblePos = "auto" # Other possibility: "middle"
     1913
    19101914        # Connection lines style
    19111915#         if wx.Platform != "__WXMAC__":
     
    27362740        return self._hilightUnfocusedBrush.GetColour()
    27372741
    2738    
     2742
    27392743    def SetFirstGradientColour(self, colour=None):
    27402744        """Sets the first gradient colour."""
     
    38893893
    38903894
    3891     def EnsureVisible(self, item):
     3895    def SetDefaultScrollVisiblePos(self, dpos):
     3896        self._defaultScrollVisiblePos = dpos
     3897
     3898
     3899    def GetDefaultScrollVisiblePos(self):
     3900        return self._defaultScrollVisiblePos
     3901
     3902
     3903    def EnsureVisible(self, item, toMiddle=None):
    38923904        """Ensure that an item is visible in CustomTreeCtrl."""
    38933905
     
    39063918                self.Expand(parent)
    39073919                parent = parent.GetParent()
    3908            
    3909         self.ScrollTo(item)
     3920       
     3921        if toMiddle is None:
     3922            toMiddle = self._defaultScrollVisiblePos == "middle"
     3923       
     3924        if toMiddle:
     3925            self.ScrollToMiddle(item)
     3926        else:
     3927            self.ScrollTo(item)
    39103928
    39113929
    39123930    def ScrollTo(self, item):
    39133931        """Scrolls the specified item into view."""
    3914 
     3932       
    39153933        if not item:
    39163934            return
     
    39543972            # Item should appear at bottom
    39553973            self.SetScrollbars(_PIXELS_PER_UNIT, _PIXELS_PER_UNIT, x/_PIXELS_PER_UNIT, y/_PIXELS_PER_UNIT, x_pos, (item_y+self.GetLineHeight(item)-client_h)/_PIXELS_PER_UNIT )
     3974
     3975
     3976    def ScrollToMiddle(self, item):
     3977        """Scrolls the specified item into the vertical middle of the view."""
     3978
     3979        if not item:
     3980            return
     3981
     3982        # We have to call this here because the label in
     3983        # question might just have been added and no screen
     3984        # update taken place.
     3985        if self._dirty:
     3986            if wx.Platform in ["__WXMSW__", "__WXMAC__"]:
     3987                self.Update()
     3988        else:
     3989            wx.YieldIfNeeded()
     3990
     3991        # now scroll to the item
     3992        item_y = item.GetY()
     3993        start_x, start_y = self.GetViewStart()
     3994        start_y *= _PIXELS_PER_UNIT
     3995
     3996        client_w, client_h = self.GetClientSize()
     3997       
     3998        target_y = item_y - (client_h - self.GetLineHeight(item))// 2
     3999        target_y = max(0, target_y)
     4000
     4001        x, y = 0, 0
     4002
     4003        x, y = self._anchor.GetSize(x, y, self)
     4004        y += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels
     4005        x += _PIXELS_PER_UNIT + 2 # one more scrollbar unit + 2 pixels
     4006        x_pos = self.GetScrollPos(wx.HORIZONTAL)
     4007
     4008        self.SetScrollbars(_PIXELS_PER_UNIT, _PIXELS_PER_UNIT, x/_PIXELS_PER_UNIT, y/_PIXELS_PER_UNIT, x_pos, target_y//_PIXELS_PER_UNIT)
    39564009
    39574010
  • branches/mbutscher/work/lib/pwiki/wikidata/original_gadfly/WikiData.py

    r190 r192  
    142142    def getContent(self, word):
    143143        try:
    144 #             if (not exists(self.getWikiWordFileName(word))):
    145 #                 raise WikiFileNotFoundException(
    146 #                         _(u"Wiki page not found for word: %s") % word)
    147 
    148             content = loadEntireTxtFile(self.getWikiWordFileName(word))
     144            try:
     145                filePath = self.getWikiWordFileName(word)
     146            except WikiFileNotFoundException:
     147                if self.wikiDocument.getWikiConfig().getboolean("main",
     148                        "wikiPageFiles_gracefulOutsideAddAndRemove", True) and \
     149                        self._guessWikiWordFileName(word) is not None:
     150                    # Page not in database but appropriate page file
     151                    # present in data directory -> refresh database and try again
     152
     153                    self.refreshDefinedContentNames(deleteFully=True)
     154                    filePath = self.getWikiWordFileName(word)
     155                else:
     156                    raise
     157
     158            if self.wikiDocument.getWikiConfig().getboolean("main",
     159                    "wikiPageFiles_gracefulOutsideAddAndRemove", True) and \
     160                    not os.path.exists(filePath):
     161                # File is missing and this should be handled gracefully
     162                self.refreshDefinedContentNames(deleteFully=True)
     163                return u""
     164
     165            content = loadEntireTxtFile(filePath)
    149166
    150167            return fileContentToUnicode(content)
     
    253270    def deleteContent(self, word):
    254271        try:
    255             fileName = self.getWikiWordFileName(word)
     272            try:
     273                fileName = self.getWikiWordFileName(word)
     274            except WikiFileNotFoundException:
     275                if self.wikiDocument.getWikiConfig().getboolean("main",
     276                        "wikiPageFiles_gracefulOutsideAddAndRemove", True):
     277                    fileName = None
     278                else:
     279                    raise
     280
    256281            self.connWrap.execSql("delete from wikiwords where word = ?",
    257282                    (word,))
    258283            self.commitNeeded = True
    259284            self.cachedContentNames = None
    260             if exists(fileName):
     285            if fileName is not None and os.path.exists(fileName):
    261286                os.unlink(fileName)
    262287        except (IOError, OSError, ValueError), e:
     
    486511        """
    487512        try:
    488             filePath = self.getWikiWordFileName(word)
     513            try:
     514                filePath = self.getWikiWordFileName(word)
     515            except WikiFileNotFoundException:
     516                if self.wikiDocument.getWikiConfig().getboolean("main",
     517                        "wikiPageFiles_gracefulOutsideAddAndRemove", True) and \
     518                        self._guessWikiWordFileName(word) is not None:
     519
     520                    self.refreshDefinedContentNames(deleteFully=True)
     521                    # Try again
     522                    filePath = self.getWikiWordFileName(word)
     523                else:
     524                    raise
     525
     526            if self.wikiDocument.getWikiConfig().getboolean("main",
     527                    "wikiPageFiles_gracefulOutsideAddAndRemove", True) and \
     528                    not os.path.exists(filePath):
     529                # File is missing and this should be handled gracefully
     530                self.refreshDefinedContentNames(deleteFully=True)
     531                return True
     532
    489533            fileSig = getFileSignatureBlock(filePath)
    490534
     
    882926
    883927
    884     def refreshDefinedContentNames(self):
     928    def refreshDefinedContentNames(self, deleteFully=False):
    885929        """
    886930        Refreshes the internal list of defined pages which
     
    890934        (creation/modif. date) if possible.
    891935       
    892         It is mainly called during rebuilding of the wiki
    893         so it must not rely on the presence of other cache
     936        With deleteFully == False it is mainly called during rebuilding
     937        of the wiki so it must not rely on the presence of other cache
    894938        information (e.g. relations)
     939       
     940        With deleteFully == True it is called if a missing or externally
     941        added file is detected and content names must be rebuilt without
     942        full rebuild of the wiki. In this case caches exist and are updated.
    895943
    896944        The self.cachedContentNames is invalidated.
     
    900948
    901949        self.cachedContentNames = None
     950
    902951        try:
    903952            # Delete words for which no file is present anymore
     
    905954                    "select filepath from wikiwords"):
    906955                if not os.path.exists(longPathEnc(os.path.join(self.dataDir, path))):
    907                     self.connWrap.execSql("delete from wikiwords "
    908                             "where filepath = ?", (path,))
    909                     self.commitNeeded = True
     956                    if not deleteFully:
     957                        self.connWrap.execSql("delete from wikiwords "
     958                                "where filepath = ?", (path,))
     959                        self.commitNeeded = True
     960                    else:
     961                        words = self.connWrap.execSqlQuerySingleColumn(
     962                                "select word from wikiwords "
     963                                "where filepath = ?", (path,))
     964                        for word in words:
     965                            self.deleteWord(word)
    910966
    911967            # Add new words:
     
    916972               
    917973                wikiWord = self._findNewWordForFile(path)
    918                
    919 #                 wikiWord = guessBaseNameByFilename(path, self.pagefileSuffix)
    920                
    921 #                 if self.execSqlQuerySingleItem(
    922 #                         "select word from wikiwords where word = ?", (wikiWord,)):
    923 #                     for i in range(20):    # "while True" is too dangerous
    924 #                         rand = createRandomString(10)
    925 #                         
    926 #                         if self.execSqlQuerySingleItem(
    927 #                                 "select word from wikiwords where word = ?",
    928 #                                 (wikiWord + u"~" + rand,)):
    929 #                             continue
    930 #                         
    931 #                         wikiWord = wikiWord + u"~" + rand
    932 #                         break
    933 #                     else:
    934974
    935975                if wikiWord is not None:
     
    9721012    def _getAllWikiFileNamesFromDisk(self):   # Used for rebuilding wiki
    9731013        try:
    974             files = glob.glob(longPathEnc(join(self.dataDir,
    975                     u'*' + self.pagefileSuffix)))
    976 
    977             return [longPathDec(basename(fn)) for fn in files]
     1014            files = glob.glob(join(self.dataDir, u'*' + self.pagefileSuffix))
    9781015           
    979 #             result = []
    980 #             for file in files:
    981 #                 word = pathDec(basename(file))
    982 #                 if word.endswith(self.pagefileSuffix):
    983 #                     word = word[:-len(self.pagefileSuffix)]
    984 #                 
    985 #                 result.append(word)
    986 #             
    987 #             return result
     1016            return [basename(fn) for fn in files]
    9881017
    9891018        except (IOError, OSError, ValueError), e:
     
    10341063        a file with that name in the data directory
    10351064        """
    1036         icf = iterCompatibleFilename(wikiWord, self.pagefileSuffix)
     1065        asciiOnly = self.wikiDocument.getWikiConfig().getboolean("main",
     1066                "wikiPageFiles_asciiOnly", False)
     1067
     1068        icf = iterCompatibleFilename(wikiWord, self.pagefileSuffix,
     1069                asciiOnly=asciiOnly)
    10371070        try:
    10381071            for i in range(30):   # "while True" would be too dangerous
     
    10431076                if len(existing) > 0:
    10441077                    continue
    1045                 if exists(longPathEnc(join(self.dataDir, fileName))):
     1078                if os.path.exists(longPathEnc(join(self.dataDir, fileName))):
    10461079                    continue
    10471080   
     
    10541087
    10551088
     1089    def _guessWikiWordFileName(self, wikiWord):
     1090        """
     1091        Try to find an existing file in self.dataDir which COULD BE the page
     1092        file for wikiWord.
     1093        Called when external adding of files should be handled gracefully.
     1094        Returns either the filename relative to self.dataDir or None.
     1095        """
     1096        try:
     1097            asciiOnly = self.wikiDocument.getWikiConfig().getboolean("main",
     1098                    "wikiPageFiles_asciiOnly", False)
     1099           
     1100            # Try first with current ascii-only setting
     1101            icf = iterCompatibleFilename(wikiWord, self.pagefileSuffix,
     1102                    asciiOnly=asciiOnly)
     1103   
     1104            for i in range(2):
     1105                fileName = icf.next()
     1106
     1107                existing = self.connWrap.execSqlQuerySingleColumn(
     1108                        "select filenamelowercase from wikiwords "
     1109                        "where filenamelowercase = ?", (fileName.lower(),))
     1110                if len(existing) > 0:
     1111                    continue
     1112                if not os.path.exists(longPathEnc(join(self.dataDir, fileName))):
     1113                    continue
     1114
     1115                return fileName
     1116
     1117            # Then the same with opposite ascii-only setting
     1118            icf = iterCompatibleFilename(wikiWord, self.pagefileSuffix,
     1119                    asciiOnly=not asciiOnly)
     1120   
     1121            for i in range(2):
     1122                fileName = icf.next()
     1123
     1124                existing = self.connWrap.execSqlQuerySingleColumn(
     1125                        "select filenamelowercase from wikiwords "
     1126                        "where filenamelowercase = ?", (fileName.lower(),))
     1127                if len(existing) > 0:
     1128                    continue
     1129                if not os.path.exists(longPathEnc(join(self.dataDir, fileName))):
     1130                    continue
     1131
     1132                return fileName
     1133           
     1134            return None
     1135        except (IOError, OSError, ValueError), e:
     1136            traceback.print_exc()
     1137            raise DbReadAccessError(e)
    10561138
    10571139
     
    17871869                    return
    17881870
     1871                asciiOnly = self.wikiDocument.getWikiConfig().getboolean("main",
     1872                        "wikiPageFiles_asciiOnly", False)
     1873
    17891874                # Find unused filename
    1790                 icf = iterCompatibleFilename(unifName, u".data")
     1875                icf = iterCompatibleFilename(unifName, u".data",
     1876                        asciiOnly=asciiOnly)
    17911877
    17921878                for i in range(30):   # "while True" would be too dangerous
     
    19392025
    19402026    _CAPABILITIES = {
    1941         "rebuild": 1
     2027        "rebuild": 1,
     2028        "filePerPage": 1   # Uses a single file per page
    19422029        }
    19432030
  • branches/mbutscher/work/lib/pwiki/wikidata/original_sqlite/WikiData.py

    r190 r192  
    179179        """
    180180        try:
    181 #             if (not exists(self.getWikiWordFileName(word))):
    182 #                 raise WikiFileNotFoundException(
    183 #                         _(u"Wiki page not found for word: %s") % word)
    184    
    185             content = loadEntireTxtFile(self.getWikiWordFileName(word))
    186    
     181            try:
     182                filePath = self.getWikiWordFileName(word)
     183            except WikiFileNotFoundException:
     184                if self.wikiDocument.getWikiConfig().getboolean("main",
     185                        "wikiPageFiles_gracefulOutsideAddAndRemove", True) and \
     186                        self._guessWikiWordFileName(word) is not None:
     187                    # Page not in database but appropriate page file
     188                    # present in data directory -> refresh database and try again
     189
     190                    self.refreshDefinedContentNames(deleteFully=True)
     191                    filePath = self.getWikiWordFileName(word)
     192                else:
     193                    raise
     194
     195            if self.wikiDocument.getWikiConfig().getboolean("main",
     196                    "wikiPageFiles_gracefulOutsideAddAndRemove", True) and \
     197                    not os.path.exists(filePath):
     198                # File is missing and this should be handled gracefully
     199                self.refreshDefinedContentNames(deleteFully=True)
     200                return u""
     201
     202            content = loadEntireTxtFile(filePath)
     203
    187204            return fileContentToUnicode(content)
    188205        except (IOError, OSError, sqlite.Error), e:
     
    283300    def deleteContent(self, word):
    284301        try:
    285             fileName = self.getWikiWordFileName(word)
     302            try:
     303                fileName = self.getWikiWordFileName(word)
     304            except WikiFileNotFoundException:
     305                if self.wikiDocument.getWikiConfig().getboolean("main",
     306                        "wikiPageFiles_gracefulOutsideAddAndRemove", True):
     307                    fileName = None
     308                else:
     309                    raise
     310
    286311            self.connWrap.execSql("delete from wikiwords where word = ?",
    287312                    (word,))
     
    505530        """
    506531        try:
    507             filePath = self.getWikiWordFileName(word)
     532            try:
     533                filePath = self.getWikiWordFileName(word)
     534            except WikiFileNotFoundException:
     535                if self.wikiDocument.getWikiConfig().getboolean("main",
     536                        "wikiPageFiles_gracefulOutsideAddAndRemove", True) and \
     537                        self._guessWikiWordFileName(word) is not None:
     538
     539                    self.refreshDefinedContentNames(deleteFully=True)
     540                    # Try again
     541                    filePath = self.getWikiWordFileName(word)
     542                else:
     543                    raise
     544
     545            if self.wikiDocument.getWikiConfig().getboolean("main",
     546                    "wikiPageFiles_gracefulOutsideAddAndRemove", True) and \
     547                    not os.path.exists(filePath):
     548                # File is missing and this should be handled gracefully
     549                self.refreshDefinedContentNames(deleteFully=True)
     550                return True
     551
    508552            fileSig = getFileSignatureBlock(filePath)
    509553
     
    511555                    "select filesignature from wikiwords where word = ?",
    512556                    (word,))
    513            
     557
    514558            return dbFileSig == fileSig
    515559        except (IOError, OSError, sqlite.Error), e:
     
    9601004
    9611005   
    962     def refreshDefinedContentNames(self):
     1006    def refreshDefinedContentNames(self, deleteFully=False):
    9631007        """
    9641008        Refreshes the internal list of defined pages which
     
    9841028                    "select filepath from wikiwords"):
    9851029                if not os.path.exists(longPathEnc(os.path.join(self.dataDir, path))):
    986                     self.connWrap.execSql("delete from wikiwords "
    987                             "where filepath = ?", (path,))
     1030                    if not deleteFully:
     1031                        self.connWrap.execSql("delete from wikiwords "
     1032                                "where filepath = ?", (path,))
     1033                        self.commitNeeded = True
     1034                    else:
     1035                        words = self.connWrap.execSqlQuerySingleColumn(
     1036                                "select word from wikiwords "
     1037                                "where filepath = ?", (path,))
     1038                        for word in words:
     1039                            self.deleteWord(word)
    9881040
    9891041            # Add new words:
     
    9941046               
    9951047                wikiWord = self._findNewWordForFile(path)
    996                
    997 #                 wikiWord = guessBaseNameByFilename(path, self.pagefileSuffix)
    998                
    999 #                 if self.execSqlQuerySingleItem(
    1000 #                         "select word from wikiwords where word = ?", (wikiWord,)):
    1001 #                     for i in range(20):    # "while True" is too dangerous
    1002 #                         rand = createRandomString(10)
    1003 #                         
    1004 #                         if self.execSqlQuerySingleItem(
    1005 #                                 "select word from wikiwords where word = ?",
    1006 #                                 (wikiWord + u"~" + rand,)):
    1007 #                             continue
    1008 #                         
    1009 #                         wikiWord = wikiWord + u"~" + rand
    1010 #                         break
    1011 #                     else:
    10121048
    10131049                if wikiWord is not None:
     
    10471083    def _getAllWikiFileNamesFromDisk(self):   # Used for rebuilding wiki
    10481084        try:
    1049             files = glob.glob(longPathEnc(join(self.dataDir,
    1050                     u'*' + self.pagefileSuffix)))
    1051 
    1052             return [longPathDec(basename(fn)) for fn in files]
     1085            files = glob.glob(join(self.dataDir, u'*' + self.pagefileSuffix))
     1086
     1087            return [basename(fn) for fn in files]
    10531088           
    10541089#             result = []
     
    11051140
    11061141
    1107 #     def isDefinedWikiWord(self, word):
    1108 #         """
    1109 #         check if a word is a valid wikiword (page name or alias)
    1110 #         Function must work for read-only wiki.
    1111 #         """
    1112 #         return self._getCachedContentNames().has_key(word)
    1113 
    1114 #     def getWikiWordsStartingWith(self, thisStr, includeAliases=False,
    1115 #             caseNormed=False):
    1116 #         """
    1117 #         get the list of words starting with thisStr. used for autocompletion.
    1118 #         Function must work for read-only wiki.
    1119 #         """
    1120 #         # Escape some characters:   # TODO more elegant
    1121 #         thisStr = thisStr.replace("[", "[[").replace("]", "[]]").replace("[[", "[[]")
    1122 #         try:
    1123 #             if caseNormed:
    1124 #                 thisStr = thisStr.lower()   # TODO More general normcase function
    1125 #                 if includeAliases:
    1126 #                     return self.connWrap.execSqlQuerySingleColumn(
    1127 #                             "select word from wikiwords where wordnormcase glob (? || '*') union "
    1128 #                             "select value from wikiwordprops where key = 'alias' and "
    1129 #                             "utf8Normcase(value) glob (? || '*')", (thisStr, thisStr))
    1130 #                 else:
    1131 #                     return self.connWrap.execSqlQuerySingleColumn("select word "
    1132 #                             "from wikiwords where wordnormcase glob (? || '*')",
    1133 #                             (thisStr,))
    1134 #             else:
    1135 #                 if includeAliases:
    1136 #                     return self.connWrap.execSqlQuerySingleColumn(
    1137 #                             "select word from wikiwords where word glob (? || '*') union "
    1138 #                             "select value from wikiwordprops where key = 'alias' and "
    1139 #                             "value glob (? || '*')", (thisStr, thisStr))
    1140 #                 else:
    1141 #                     return self.connWrap.execSqlQuerySingleColumn("select word "
    1142 #                             "from wikiwords where word glob (? || '*')",
    1143 #                             (thisStr,))
    1144 #
    1145 #
    1146 #         except (IOError, OSError, sqlite.Error), e:
    1147 #             traceback.print_exc()
    1148 #             raise DbReadAccessError(e)
    1149 #         
    1150 #         return pathEnc(join(self.dataDir, path))
    1151 
    1152 
    11531142    def createWikiWordFileName(self, wikiWord):
    11541143        """
     
    11561145        a file with that name in the data directory
    11571146        """
    1158         icf = iterCompatibleFilename(wikiWord, self.pagefileSuffix)
     1147        asciiOnly = self.wikiDocument.getWikiConfig().getboolean("main",
     1148                "wikiPageFiles_asciiOnly", False)
     1149
     1150        icf = iterCompatibleFilename(wikiWord, self.pagefileSuffix,
     1151                asciiOnly=asciiOnly)
    11591152        for i in range(30):   # "while True" would be too dangerous
    11601153            fileName = icf.next()
     
    11701163
    11711164        return None
     1165
     1166
     1167    def _guessWikiWordFileName(self, wikiWord):
     1168        """
     1169        Try to find an existing file in self.dataDir which COULD BE the page
     1170        file for wikiWord.
     1171        Called when external adding of files should be handled gracefully.
     1172        Returns either the filename relative to self.dataDir or None.
     1173        """
     1174        try:
     1175            asciiOnly = self.wikiDocument.getWikiConfig().getboolean("main",
     1176                    "wikiPageFiles_asciiOnly", False)
     1177           
     1178            # Try first with current ascii-only setting
     1179            icf = iterCompatibleFilename(wikiWord, self.pagefileSuffix,
     1180                    asciiOnly=asciiOnly)
     1181   
     1182            for i in range(2):
     1183                fileName = icf.next()
     1184
     1185                existing = self.connWrap.execSqlQuerySingleColumn(
     1186                        "select filenamelowercase from wikiwords "
     1187                        "where filenamelowercase = ?", (fileName.lower(),))
     1188                if len(existing) > 0:
     1189                    continue
     1190                if not os.path.exists(longPathEnc(join(self.dataDir, fileName))):
     1191                    continue
     1192
     1193                return fileName
     1194
     1195            # Then the same with opposite ascii-only setting
     1196            icf = iterCompatibleFilename(wikiWord, self.pagefileSuffix,
     1197                    asciiOnly=not asciiOnly)
     1198   
     1199            for i in range(2):
     1200                fileName = icf.next()
     1201
     1202                existing = self.connWrap.execSqlQuerySingleColumn(
     1203                        "select filenamelowercase from wikiwords "
     1204                        "where filenamelowercase = ?", (fileName.lower(),))
     1205                if len(existing) > 0:
     1206                    continue
     1207                if not os.path.exists(longPathEnc(join(self.dataDir, fileName))):
     1208                    continue
     1209
     1210                return fileName
     1211           
     1212            return None
     1213        except (IOError, OSError, sqlite.Error), e:
     1214            traceback.print_exc()
     1215            raise DbReadAccessError(e)
    11721216
    11731217
     
    12381282
    12391283
    1240 #     def getWikiLinksStartingWith(self, thisStr, includeAliases=False,
    1241 #             caseNormed=False):
    1242 #         "get the list of words starting with thisStr. used for autocompletion."
    1243 #         words = self.getAllDefinedContentNames()
    1244 #         if includeAliases:
    1245 #             words.extend(self.getAllAliases())
    1246 #         
    1247 #         if caseNormed:
    1248 #             thisStr = thisStr.lower()   # TODO More general normcase function
    1249 #             startingWith = [word for word in words
    1250 #                     if word.lower().startswith(thisStr)]
    1251 #             return startingWith
    1252 #         else:
    1253 #             startingWith = [word for word in words if word.startswith(thisStr)]
    1254 #             return startingWith
    1255 
    1256 
    1257 #     def getWikiWordsWith(self, thisStr, includeAliases=False):
    1258 #         """
    1259 #         get the list of words with thisStr in them,
    1260 #         if possible first these which start with thisStr.
    1261 #         Function must work for read-only wiki.
    1262 #         """
    1263 #         thisStr = thisStr.lower()   # TODO More general normcase function
    1264 #
    1265 #         try:
    1266 #             result1 = self.connWrap.execSqlQuerySingleColumn(
    1267 #                     "select word from wikiwords where wordnormcase like (? || '%')",
    1268 #                     (thisStr,))
    1269 #
    1270 #             if includeAliases:
    1271 #                 result1 += self.connWrap.execSqlQuerySingleColumn(
    1272 #                         "select value from wikiwordprops where key = 'alias' and "
    1273 #                         "utf8Normcase(value) like (? || '%')", (thisStr,))
    1274 #     
    1275 #             result2 = self.connWrap.execSqlQuerySingleColumn(
    1276 #                     "select word from wikiwords "
    1277 #                     "where wordnormcase like ('%' || ? || '%') and "
    1278 #                     "wordnormcase not like (? || '%') and word not glob '[[]*'",
    1279 #                     (thisStr, thisStr))
    1280 #     
    1281 #             if includeAliases:
    1282 #                 result2 += self.connWrap.execSqlQuerySingleColumn(
    1283 #                         "select value from wikiwordprops where key = 'alias' and "
    1284 #                         "utf8Normcase(value) like ('%' || ? || '%') and "
    1285 #                         "utf8Normcase(value) not like (? || '%')",
    1286 #                         (thisStr, thisStr))
    1287 #                         
    1288 #             coll = self.wikiDocument.getCollator()
    1289 #             
    1290 #             coll.sort(result1)
    1291 #             coll.sort(result2)
    1292 #
    1293 #             return result1 + result2
    1294 #         except (IOError, OSError, sqlite.Error), e:
    1295 #             traceback.print_exc()
    1296 #             raise DbReadAccessError(e)
    1297 
    1298 
    1299 
    13001284    def getWikiWordsModifiedWithin(self, startTime, endTime):
    13011285        """
     
    18761860                    return
    18771861
     1862                asciiOnly = self.wikiDocument.getWikiConfig().getboolean("main",
     1863                        "wikiPageFiles_asciiOnly", False)
     1864
    18781865                # Find unused filename
    1879                 icf = iterCompatibleFilename(unifName, u".data")
     1866                icf = iterCompatibleFilename(unifName, u".data",
     1867                        asciiOnly=asciiOnly)
    18801868
    18811869                for i in range(30):   # "while True" would be too dangerous
     
    19741962        "rebuild": 1,
    19751963        "compactify": 1,     # = sqlite vacuum
     1964        "filePerPage": 1   # Uses a single file per page
    19761965#         "versioning": 1,     # TODO (old versioning)
    19771966#         "plain text import":1   # Is already plain text     
  • branches/mbutscher/work/lib/pwiki/wxHelper.py

    r190 r192  
    533533                    id = self.iconLookupCache[iconname][0]
    534534
    535                 self.iconLookupCache[iconname] = (id, bitmap)
     535                self.iconLookupCache[iconname] = (id, iconFile, bitmap)
    536536            except Exception, e:
    537537                traceback.print_exc()
     
    546546        """
    547547        for k in self.iconLookupCache.keys():
    548             self.iconLookupCache[k] = (self.iconLookupCache[k][0], None)
     548            self.iconLookupCache[k] = self.iconLookupCache[k][0:2] + (None,)
    549549
    550550
     
    556556        """
    557557        try:
    558             bitmap = self.iconLookupCache[iconname][1]
     558            bitmap = self.iconLookupCache[iconname][2]
    559559            if bitmap is not None:
    560560                return bitmap
     
    564564            bitmap = wx.Bitmap(iconFile, wx.BITMAP_TYPE_GIF)
    565565           
    566             self.iconLookupCache[iconname] = (self.iconLookupCache[iconname][0],
    567                     bitmap)
     566            self.iconLookupCache[iconname] = self.iconLookupCache[k][0:2] + \
     567                    (bitmap,)
     568
    568569            return bitmap
    569570
     
    582583            return -1
    583584
     585
     586    def lookupIconPath(self, iconname):
     587        """
     588        Returns the path to icon file of the requested icon.
     589        If icon is unknown, -1 is returned.
     590        """
     591        try:
     592            return self.iconLookupCache[iconname][1]
     593        except KeyError:
     594            return None
    584595
    585596    def resolveIconDescriptor(self, desc, default=None):
  • branches/mbutscher/work/wikidpad_unicode.iss

    r190 r192  
    3636Source: dist\WikidPad_*.po; DestDir: {app}; Components: Program_files; Flags: ignoreversion sortfilesbyextension
    3737Source: dist\langlist.txt; DestDir: {app}; Components: Program_files; Flags: replacesameversion ignoreversion
    38 Source: dist\gadfly.zip; DestDir: {app}; Components: Program_files
    39 Source: dist\library.zip; DestDir: {app}; Components: Program_files
     38Source: dist\gadfly.zip; DestDir: {app}; Components: Program_files; Flags: nocompression
     39Source: dist\library.zip; DestDir: {app}; Components: Program_files; Flags: nocompression
    4040Source: Microsoft.VC90.CRT.manifest; DestDir: {app}
    4141Source: winBinAdditions\msvcp90.dll; DestDir: {app}
     
    5555SolidCompression=true
    5656AppName=WikidPad
    57 AppVerName=WikidPad 2.0beta02
     57AppVerName=WikidPad 2.0beta03
    5858DefaultDirName={pf}\WikidPad
    5959DefaultGroupName=WikidPad
    6060AppID={{22A83C29-58A8-4CAB-8EDC-918D74F8429E}
    61 VersionInfoVersion=2.0.102.0
    62 VersionInfoTextVersion=WikidPad 2.0beta02
     61VersionInfoVersion=2.0.103.0
     62VersionInfoTextVersion=WikidPad 2.0beta03
    6363LicenseFile=C:\DATEN\Projekte\Wikidpad\Current\license.txt
    6464AllowNoIcons=true
    6565ShowLanguageDialog=yes
    6666Compression=lzma/ultra
    67 OutputBaseFilename=WikidPad-2.0beta02
     67OutputBaseFilename=WikidPad-2.0beta03
    6868InternalCompressLevel=ultra
    6969AppCopyright=© 2005-2009 Jason Horman, Michael Butscher, Gerhard Reitmayr
Note: See TracChangeset for help on using the changeset viewer.