CSV catalog pluggin remove \n and \r\n in comments

This commit is contained in:
Sengian 2010-07-14 19:58:25 +02:00
commit a68fb07c41
28 changed files with 483 additions and 415 deletions

View File

@ -1,24 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) --> <!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg <svg
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://web.resource.org/cc/" xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128" width="128"
height="128" height="128"
id="svg1307" id="svg1307"
sodipodi:version="0.32" sodipodi:version="0.32"
inkscape:version="0.43" inkscape:version="0.47 r22583"
version="1.0" version="1.0"
sodipodi:docbase="/home/pinheiro/Documents/pics/new oxygen/svg" sodipodi:docname="donate.svg">
sodipodi:docname="love.svg">
<defs <defs
id="defs1309"> id="defs1309">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 64 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="128 : 64 : 1"
inkscape:persp3d-origin="64 : 42.666667 : 1"
id="perspective44" />
<linearGradient <linearGradient
inkscape:collect="always" inkscape:collect="always"
id="linearGradient2231"> id="linearGradient2231">
@ -180,8 +187,8 @@
inkscape:pageopacity="0.0" inkscape:pageopacity="0.0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="7.851329" inkscape:zoom="7.851329"
inkscape:cx="92.691163" inkscape:cx="60.937831"
inkscape:cy="92.473338" inkscape:cy="61.488995"
inkscape:current-layer="layer1" inkscape:current-layer="layer1"
showgrid="false" showgrid="false"
inkscape:document-units="px" inkscape:document-units="px"
@ -189,10 +196,11 @@
guidetolerance="0.1px" guidetolerance="0.1px"
showguides="true" showguides="true"
inkscape:guide-bbox="true" inkscape:guide-bbox="true"
inkscape:window-width="1106" inkscape:window-width="1680"
inkscape:window-height="958" inkscape:window-height="997"
inkscape:window-x="597" inkscape:window-x="-4"
inkscape:window-y="25"> inkscape:window-y="30"
inkscape:window-maximized="1">
<sodipodi:guide <sodipodi:guide
orientation="horizontal" orientation="horizontal"
position="32.487481" position="32.487481"
@ -245,26 +253,19 @@
id="path2276" id="path2276"
d="M 50.892799,3.2812959 L 50.892799,0.48658747 L 50.892799,3.2812959 z " d="M 50.892799,3.2812959 L 50.892799,0.48658747 L 50.892799,3.2812959 z "
style="fill:#ffffff;fill-opacity:0.75688076;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1" /> style="fill:#ffffff;fill-opacity:0.75688076;fill-rule:nonzero;stroke:none;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1" />
<path
sodipodi:type="arc"
style="opacity:0.38139535;fill:url(#radialGradient3297);fill-opacity:1.0;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
id="path3289"
sodipodi:cx="63.912209"
sodipodi:cy="115.70919"
sodipodi:rx="63.912209"
sodipodi:ry="12.641975"
d="M 127.82442 115.70919 A 63.912209 12.641975 0 1 1 0,115.70919 A 63.912209 12.641975 0 1 1 127.82442 115.70919 z"
transform="matrix(1,0,0,0.416667,0,74.87151)" />
<path <path
style="fill:url(#radialGradient2335);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="fill:url(#radialGradient2335);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 35.325021,6.2016208 C 32.278871,6.2210338 29.045555,6.6687791 25.645673,7.6089386 C 5.9380713,13.058619 0.404709,29.342113 5.3805953,48.506873 C 12.126047,74.487157 36.855395,101.02725 64.150803,115.92895 L 64.150803,116.02417 C 64.162016,116.00826 64.173539,115.99248 64.184766,115.97656 C 64.195995,115.99248 64.207516,116.00826 64.218732,116.02417 L 64.218732,115.92895 C 90.473794,101.59521 116.24349,74.487157 122.98895,48.506873 C 127.96481,29.342113 122.43148,13.058619 102.72386,7.6089386 C 83.422254,2.2715258 69.549778,12.840101 64.184766,27.183808 C 59.764775,15.366673 49.572303,6.1108179 35.325021,6.2016208 z " d="M 35.325021,6.2016208 C 32.278871,6.2210338 29.045555,6.6687791 25.645673,7.6089386 C 5.9380713,13.058619 0.404709,29.342113 5.3805953,48.506873 C 12.126047,74.487157 36.855395,101.02725 64.150803,115.92895 L 64.150803,116.02417 C 64.162016,116.00826 64.173539,115.99248 64.184766,115.97656 C 64.195995,115.99248 64.207516,116.00826 64.218732,116.02417 L 64.218732,115.92895 C 90.473794,101.59521 116.24349,74.487157 122.98895,48.506873 C 127.96481,29.342113 122.43148,13.058619 102.72386,7.6089386 C 83.422254,2.2715258 69.549778,12.840101 64.184766,27.183808 C 59.764775,15.366673 49.572303,6.1108179 35.325021,6.2016208 z "
id="path2245" id="path2245"
sodipodi:nodetypes="cssccsccsscc" /> sodipodi:nodetypes="cssccsccsscc" />
<g
id="g2850">
<path <path
id="path2369" sodipodi:nodetypes="cssccsccsscc"
d="M 35.325021,6.2016208 C 32.278871,6.2210338 29.045555,6.6687791 25.645673,7.6089386 C 5.9380713,13.058619 0.404709,29.342113 5.3805953,48.506873 C 12.126047,74.487157 37.113186,101.16799 64.150803,115.92895 L 64.150803,116.02417 C 64.162016,116.00826 64.173539,115.99248 64.184766,115.97656 C 64.195995,115.99248 64.207516,116.00826 64.218732,116.02417 L 64.218732,115.92895 C 90.398445,101.63635 116.24349,74.487157 122.98895,48.506873 C 127.96481,29.342113 122.43148,13.058619 102.72386,7.6089386 C 83.422254,2.2715258 69.549778,12.840101 64.184766,27.183808 C 59.764775,15.366673 49.572303,6.1108179 35.325021,6.2016208 z "
style="opacity:0.4713115;fill:url(#linearGradient2379);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="opacity:0.4713115;fill:url(#linearGradient2379);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:nodetypes="cssccsccsscc" /> d="M 35.325021,6.2016208 C 32.278871,6.2210338 29.045555,6.6687791 25.645673,7.6089386 C 5.9380713,13.058619 0.404709,29.342113 5.3805953,48.506873 C 12.126047,74.487157 37.113186,101.16799 64.150803,115.92895 L 64.150803,116.02417 C 64.162016,116.00826 64.173539,115.99248 64.184766,115.97656 C 64.195995,115.99248 64.207516,116.00826 64.218732,116.02417 L 64.218732,115.92895 C 90.398445,101.63635 116.24349,74.487157 122.98895,48.506873 C 127.96481,29.342113 122.43148,13.058619 102.72386,7.6089386 C 83.422254,2.2715258 69.549778,12.840101 64.184766,27.183808 C 59.764775,15.366673 49.572303,6.1108179 35.325021,6.2016208 z "
id="path2369" />
</g>
<path <path
style="opacity:0.1762295;fill:url(#linearGradient2331);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3.29999995;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" style="opacity:0.1762295;fill:url(#linearGradient2331);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3.29999995;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 34.451605,6.2067207 C 31.659392,6.2976073 28.7301,6.7682297 25.648957,7.6202497 C 7.7889432,12.559022 1.5815371,26.389172 4.2759909,43.204304 C 27.13595,75.72273 65.297627,95.42612 91.41193,91.971053 C 105.43169,77.948778 119.04939,63.70497 122.99185,48.520401 C 127.96773,29.355639 122.42255,13.069929 102.71494,7.6202497 C 83.413331,2.2828362 69.546961,12.850845 64.181949,27.194552 C 59.761957,15.377418 49.555176,6.1159177 35.307894,6.2067207 C 35.022317,6.2085406 34.740456,6.1973187 34.451605,6.2067207 z " d="M 34.451605,6.2067207 C 31.659392,6.2976073 28.7301,6.7682297 25.648957,7.6202497 C 7.7889432,12.559022 1.5815371,26.389172 4.2759909,43.204304 C 27.13595,75.72273 65.297627,95.42612 91.41193,91.971053 C 105.43169,77.948778 119.04939,63.70497 122.99185,48.520401 C 127.96773,29.355639 122.42255,13.069929 102.71494,7.6202497 C 83.413331,2.2828362 69.546961,12.850845 64.181949,27.194552 C 59.761957,15.377418 49.555176,6.1159177 35.307894,6.2067207 C 35.022317,6.2085406 34.740456,6.1973187 34.451605,6.2067207 z "

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,234 +1,176 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 12.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 51448) --> <!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg <svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://web.resource.org/cc/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.0" version="1.0"
id="Livello_1"
width="128" width="128"
height="128" height="128"
viewBox="0 0 139 139" viewBox="0 0 139 139"
overflow="visible" id="Livello_1"
enable-background="new 0 0 139 139"
xml:space="preserve" xml:space="preserve"
sodipodi:version="0.32" style="overflow:visible"><defs
inkscape:version="0.45+devel"
sodipodi:docname="system-help.svgz"
inkscape:output_extension="org.inkscape.output.svgz.inkscape"
style="overflow:visible"><metadata
id="metadata3164"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs3162"><filter id="defs3162"><filter
inkscape:collect="always"
x="-0.132641" x="-0.132641"
width="1.265282"
y="-0.34752154" y="-0.34752154"
width="1.265282"
height="1.6950431" height="1.6950431"
color-interpolation-filters="sRGB"
id="filter3547"><feGaussianBlur id="filter3547"><feGaussianBlur
inkscape:collect="always" id="feGaussianBlur3549"
stdDeviation="2.7512044" stdDeviation="2.7512044" /></filter><filter
id="feGaussianBlur3549" /></filter><filter color-interpolation-filters="sRGB"
inkscape:collect="always"
id="filter5097"><feGaussianBlur id="filter5097"><feGaussianBlur
inkscape:collect="always" id="feGaussianBlur5099"
stdDeviation="2.32" stdDeviation="2.32" /></filter><filter
id="feGaussianBlur5099" /></filter><filter
inkscape:collect="always"
x="-0.143268" x="-0.143268"
width="1.286536"
y="-0.072184406" y="-0.072184406"
width="1.286536"
height="1.1443688" height="1.1443688"
color-interpolation-filters="sRGB"
id="filter5125"><feGaussianBlur id="filter5125"><feGaussianBlur
inkscape:collect="always" id="feGaussianBlur5127"
stdDeviation="1.91024" stdDeviation="1.91024" /></filter></defs>
id="feGaussianBlur5127" /></filter></defs><sodipodi:namedview
inkscape:window-height="697"
inkscape:window-width="1024"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
inkscape:zoom="2.9352518"
inkscape:cx="99.496726"
inkscape:cy="69.329657"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:current-layer="Livello_1"
height="128px"
width="128px" />
<filter <filter
color-interpolation-filters="sRGB"
id="AI_Sfocatura_4"> id="AI_Sfocatura_4">
<feGaussianBlur <feGaussianBlur
stdDeviation="4" id="feGaussianBlur3096"
id="feGaussianBlur3096" /> stdDeviation="4" />
</filter> </filter>
<filter <filter
color-interpolation-filters="sRGB"
id="AI_Sfocatura_2"> id="AI_Sfocatura_2">
<feGaussianBlur <feGaussianBlur
stdDeviation="2" id="feGaussianBlur3099"
id="feGaussianBlur3099" /> stdDeviation="2" />
</filter> </filter>
<radialGradient <radialGradient
id="XMLID_12_"
cx="69.600098" cx="69.600098"
cy="69.576698" cy="69.576698"
r="58" r="58"
gradientTransform="matrix(1,0,0,-0.1823,0,134.8566)" id="XMLID_12_"
gradientUnits="userSpaceOnUse"> gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,-0.1823,0,134.8566)">
<stop <stop
offset="0" id="stop3102"
style="stop-color:#000000" style="stop-color:#000000;stop-opacity:1"
id="stop3102" /> offset="0" />
<stop <stop
offset="1" id="stop3104"
style="stop-color:#000000;stop-opacity:0;" style="stop-color:#000000;stop-opacity:0"
id="stop3104" /> offset="1" />
</radialGradient> </radialGradient>
<circle <circle
sodipodi:ry="58" cx="69.599998"
sodipodi:rx="58"
sodipodi:cy="69.599998"
sodipodi:cx="69.599998"
style="opacity:0.7;fill:#000000;fill-opacity:1;stroke:none;filter:url(#filter5097)"
id="circle5091"
r="58"
cy="69.599998" cy="69.599998"
cx="69.599998" r="58"
transform="matrix(1.0859375,0,0,1.0859375,-3.9093733,-8.2531233)" /><ellipse transform="matrix(1.0859375,0,0,1.0859375,-3.9093733,-8.2531233)"
cx="69.599998" id="circle5091"
cy="122.173" style="opacity:0.7;fill:#000000;fill-opacity:1;stroke:none;filter:url(#filter5097)" />
rx="58"
ry="10.573"
id="ellipse3106"
style="opacity:0.6;fill:url(#XMLID_12_)"
sodipodi:cx="69.599998"
sodipodi:cy="122.173"
sodipodi:rx="58"
sodipodi:ry="10.573"
transform="translate(-9.9998474e-2,1.9102535)" />
<radialGradient <radialGradient
id="XMLID_13_"
cx="69.600098" cx="69.600098"
cy="69.600098" cy="69.600098"
r="58" r="58"
id="XMLID_13_"
gradientUnits="userSpaceOnUse"> gradientUnits="userSpaceOnUse">
<stop <stop
offset="0.6154" id="stop3113"
style="stop-color:#EEEEEE" style="stop-color:#eeeeee;stop-opacity:1"
id="stop3113" /> offset="0.61540002" />
<stop <stop
offset="0.8225" id="stop3115"
style="stop-color:#DDDDDD" style="stop-color:#dddddd;stop-opacity:1"
id="stop3115" /> offset="0.82249999" />
<stop <stop
offset="1" id="stop3117"
style="stop-color:#FFFFFF" style="stop-color:#ffffff;stop-opacity:1"
id="stop3117" /> offset="1" />
</radialGradient> </radialGradient>
<circle <circle
cx="69.599998" cx="69.599998"
cy="69.599998" cy="69.599998"
r="58" r="58"
transform="matrix(1.0859375,0,0,1.0859375,-3.9093733,-8.2531233)"
id="circle3119" id="circle3119"
style="fill:url(#XMLID_13_)" style="fill:url(#XMLID_13_)" />
sodipodi:cx="69.599998"
sodipodi:cy="69.599998"
sodipodi:rx="58"
sodipodi:ry="58"
transform="matrix(1.0859375,0,0,1.0859375,-3.9093733,-8.2531233)" />
<linearGradient <linearGradient
id="XMLID_14_"
gradientUnits="userSpaceOnUse"
x1="27.6001" x1="27.6001"
y1="69.600098" y1="69.600098"
x2="111.6001" x2="111.6001"
y2="69.600098" y2="69.600098"
id="XMLID_14_"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0859375,0,0,1.0859375,-3.9093733,-8.2531233)"> gradientTransform="matrix(1.0859375,0,0,1.0859375,-3.9093733,-8.2531233)">
<stop <stop
offset="0" id="stop3122"
style="stop-color:#2A94EC" style="stop-color:#2a94ec;stop-opacity:1"
id="stop3122" /> offset="0" />
<stop <stop
offset="1" id="stop3124"
style="stop-color:#0057AE" style="stop-color:#0057ae;stop-opacity:1"
id="stop3124" /> offset="1" />
</linearGradient> </linearGradient>
<path <path
d="M 26.062502,67.328127 C 26.062502,92.477355 46.522651,112.9375 71.671877,112.9375 C 96.821104,112.9375 117.28125,92.477355 117.28125,67.328127 C 117.28125,42.178901 96.821104,21.718753 71.671877,21.718753 C 46.522651,21.718753 26.062502,42.178901 26.062502,67.328127 z" d="m 26.062502,67.328127 c 0,25.149228 20.460149,45.609373 45.609375,45.609373 25.149227,0 45.609373,-20.460145 45.609373,-45.609373 0,-25.149226 -20.460146,-45.609374 -45.609373,-45.609374 -25.149226,0 -45.609375,20.460148 -45.609375,45.609374 z"
id="path3126" id="path3126"
style="fill:url(#XMLID_14_)" /> style="fill:url(#XMLID_14_)" />
<g <g
transform="matrix(1.0859375,0,0,1.0859375,-3.9093733,-8.2531233)"
id="circle22111" id="circle22111"
cy="92" style="opacity:0.3;filter:url(#filter3547)">
rx="36"
ry="36"
cx="343.99899"
enable-background="new "
style="opacity:0.3;filter:url(#filter3547)"
transform="matrix(1.0859375,0,0,1.0859375,-3.9093733,-8.2531233)">
<path <path
d="M 77.041,104.759 C 63.767,106.115 50.122,103.11 46.565,98.042 C 43.007,92.976 50.885,87.768 64.16,86.41 C 77.434,85.054 91.079,88.058 94.637,93.126 C 98.193,98.194 90.315,103.401 77.041,104.759 z" d="M 77.041,104.759 C 63.767,106.115 50.122,103.11 46.565,98.042 43.007,92.976 50.885,87.768 64.16,86.41 c 13.274,-1.356 26.919,1.648 30.477,6.716 3.556,5.068 -4.322,10.275 -17.596,11.633 z"
id="path3129" id="path3129"
style="fill:#a8dde0" /> style="fill:#a8dde0" />
</g> </g>
<linearGradient <linearGradient
id="circle16776_1_"
gradientUnits="userSpaceOnUse"
x1="135.5601" x1="135.5601"
y1="417.66461" y1="417.66461"
x2="161.87621" x2="161.87621"
y2="417.66461" y2="417.66461"
id="circle16776_1_"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,1.7280523,1.7280523,0,-650.07477,-218.71693)"> gradientTransform="matrix(0,1.7280523,1.7280523,0,-650.07477,-218.71693)">
<stop <stop
offset="0" id="stop3132"
style="stop-color:#FFFFFF" style="stop-color:#ffffff;stop-opacity:1"
id="stop3132" /> offset="0" />
<stop <stop
offset="1" id="stop3134"
style="stop-color:#ffffff;stop-opacity:0;" style="stop-color:#ffffff;stop-opacity:0"
id="stop3134" /> offset="1" />
</linearGradient> </linearGradient>
<path <path
d="m 71.671877,24.06655 c -21.383195,0 -39.252297,14.70468 -43.558039,34.283047 8.584336,7.792687 24.872313,-3.99082 43.558039,-3.99082 18.685727,0 34.974783,11.783507 43.558033,3.99082 C 110.92417,38.77123 93.056158,24.06655 71.671877,24.06655 z"
id="circle16776" id="circle16776"
enable-background="new "
d="M 71.671877,24.06655 C 50.288682,24.06655 32.41958,38.77123 28.113838,58.349597 C 36.698174,66.142284 52.986151,54.358777 71.671877,54.358777 C 90.357604,54.358777 106.64666,66.142284 115.22991,58.349597 C 110.92417,38.77123 93.056158,24.06655 71.671877,24.06655 z"
style="opacity:0.8;fill:url(#circle16776_1_)" /> style="opacity:0.8;fill:url(#circle16776_1_)" />
<g <g
id="g3137" transform="matrix(1.0859375,0,0,1.0859375,-3.9093733,-8.2531233)"
transform="matrix(1.0859375,0,0,1.0859375,-3.9093733,-8.2531233)"> id="g3137">
<defs <defs
id="defs3139"><path id="defs3139"><path
id="XMLID_10_" d="m 27.6,69.6 c 0,23.159 18.841,42 42,42 23.159,0 42,-18.841 42,-42 0,-23.159 -18.841,-42 -42,-42 -23.159,0 -42,18.841 -42,42 z"
d="M 27.6,69.6 C 27.6,92.759 46.441,111.6 69.6,111.6 C 92.759,111.6 111.6,92.759 111.6,69.6 C 111.6,46.441 92.759,27.6 69.6,27.6 C 46.441,27.6 27.6,46.441 27.6,69.6 z" /></defs> id="XMLID_10_" /></defs>
<clipPath <clipPath
id="XMLID_6_"> id="XMLID_6_">
<use <use
xlink:href="#XMLID_10_"
id="use3143" id="use3143"
x="0" x="0"
y="0" y="0"
width="139" width="139"
height="139" /> height="139"
xlink:href="#XMLID_10_" />
</clipPath> </clipPath>
<g <g
clip-path="url(#XMLID_6_)" clip-path="url(#XMLID_6_)"
id="g3145" id="g3145"
style="filter:url(#AI_Sfocatura_2)"> style="filter:url(#AI_Sfocatura_2)">
<path <path
d="M 27.6,69.6 C 27.6,92.759 46.441,111.6 69.6,111.6 C 92.759,111.6 111.6,92.759 111.6,69.6 C 111.6,46.441 92.759,27.6 69.6,27.6 C 46.441,27.6 27.6,46.441 27.6,69.6 z" d="m 27.6,69.6 c 0,23.159 18.841,42 42,42 23.159,0 42,-18.841 42,-42 0,-23.159 -18.841,-42 -42,-42 -23.159,0 -42,18.841 -42,42 z"
id="path3147" id="path3147"
style="fill:none;stroke:#00316e;stroke-width:2" /> style="fill:none;stroke:#00316e;stroke-width:2" />
</g> </g>
@ -240,30 +182,22 @@
transform="matrix(1.0859375,0,0,1.1113796,-3.201342,-9.3177223)" transform="matrix(1.0859375,0,0,1.1113796,-3.201342,-9.3177223)"
id="g5119" id="g5119"
style="fill:#00316e;filter:url(#filter5125)"><path style="fill:#00316e;filter:url(#filter5125)"><path
style="fill:#00316e" d="m 63.37,80.089 -0.178,-2.343 c -0.18,-4.598 1.248,-9.284 5.259,-14.062 2.853,-3.424 5.169,-6.398 5.169,-9.463 0,-3.064 -2.049,-5.227 -6.418,-5.318 -3.029,0 -6.506,0.992 -8.913,2.614 l -2.941,-9.733 c 3.208,-1.894 8.467,-3.696 14.885,-3.696 11.677,0 17.115,6.58 17.115,13.97 0,6.939 -4.279,11.357 -7.667,15.231 -3.209,3.605 -4.635,7.121 -4.546,11.177 l 0,1.622 -11.765,0 0,0.001 z"
d="M 63.37,80.089 L 63.192,77.746 C 63.012,73.148 64.44,68.462 68.451,63.684 C 71.304,60.26 73.62,57.286 73.62,54.221 C 73.62,51.157 71.571,48.994 67.202,48.903 C 64.173,48.903 60.696,49.895 58.289,51.517 L 55.348,41.784 C 58.556,39.89 63.815,38.088 70.233,38.088 C 81.91,38.088 87.348,44.668 87.348,52.058 C 87.348,58.997 83.069,63.415 79.681,67.289 C 76.472,70.894 75.046,74.41 75.135,78.466 L 75.135,80.088 L 63.37,80.088 L 63.37,80.089 z" id="path5121"
id="path5121" /><circle style="fill:#00316e" /><circle
style="fill:#00316e"
sodipodi:ry="8"
sodipodi:rx="8"
sodipodi:cy="93.599998"
sodipodi:cx="69.599998"
cx="69.599998" cx="69.599998"
cy="93.599998" cy="93.599998"
r="8" r="8"
id="circle5123" /></g><g id="circle5123"
id="g5101" style="fill:#00316e" /></g><g
transform="matrix(1.0859375,0,0,1.0859375,-3.201342,-8.2531233)"><path transform="matrix(1.0859375,0,0,1.0859375,-3.201342,-8.2531233)"
id="g5101"><path
d="m 63.37,80.089 -0.178,-2.343 c -0.18,-4.598 1.248,-9.284 5.259,-14.062 2.853,-3.424 5.169,-6.398 5.169,-9.463 0,-3.064 -2.049,-5.227 -6.418,-5.318 -3.029,0 -6.506,0.992 -8.913,2.614 l -2.941,-9.733 c 3.208,-1.894 8.467,-3.696 14.885,-3.696 11.677,0 17.115,6.58 17.115,13.97 0,6.939 -4.279,11.357 -7.667,15.231 -3.209,3.605 -4.635,7.121 -4.546,11.177 l 0,1.622 -11.765,0 0,0.001 z"
id="path3157" id="path3157"
d="M 63.37,80.089 L 63.192,77.746 C 63.012,73.148 64.44,68.462 68.451,63.684 C 71.304,60.26 73.62,57.286 73.62,54.221 C 73.62,51.157 71.571,48.994 67.202,48.903 C 64.173,48.903 60.696,49.895 58.289,51.517 L 55.348,41.784 C 58.556,39.89 63.815,38.088 70.233,38.088 C 81.91,38.088 87.348,44.668 87.348,52.058 C 87.348,58.997 83.069,63.415 79.681,67.289 C 76.472,70.894 75.046,74.41 75.135,78.466 L 75.135,80.088 L 63.37,80.088 L 63.37,80.089 z"
style="fill:#ffffff" /><circle style="fill:#ffffff" /><circle
id="circle3159"
r="8"
cy="93.599998"
cx="69.599998" cx="69.599998"
sodipodi:cx="69.599998" cy="93.599998"
sodipodi:cy="93.599998" r="8"
sodipodi:rx="8" id="circle3159"
sodipodi:ry="8"
style="fill:#ffffff" /></g> style="fill:#ffffff" /></g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
resources/images/lt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 B

View File

@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
www.elpais.com/diario/
'''
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
class ElPaisImpresa(BasicNewsRecipe):
title = 'El País - edicion impresa'
__author__ = 'Darko Miletic'
description = 'el periodico global en Español'
publisher = 'EDICIONES EL PAIS, S.L.'
category = 'news, politics,Spain,actualidad,noticias,informacion,videos,fotografias,audios,graficos,nacional,internacional,deportes,economia,tecnologia,cultura,gente,television,sociedad,opinion,blogs,foros,chats,encuestas,entrevistas,participacion'
no_stylesheets = True
encoding = 'latin1'
use_embedded_content = False
language = 'es'
publication_type = 'newspaper'
masthead_url = 'http://www.elpais.com/im/tit_logo_global.gif'
index = 'http://www.elpais.com/diario/'
extra_css = ' p{text-align: justify} body{ text-align: left; font-family: Georgia,"Times New Roman",Times,serif } h2{font-family: Arial,Helvetica,sans-serif} img{margin-bottom: 0.4em} '
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
feeds = [
(u'Internacional' , index + u'internacional/' )
,(u'España' , index + u'espana/' )
,(u'Economia' , index + u'economia/' )
,(u'Opinion' , index + u'opinion/' )
,(u'Viñetas' , index + u'vineta/' )
,(u'Sociedad' , index + u'sociedad/' )
,(u'Cultura' , index + u'cultura/' )
,(u'Tendencias' , index + u'tendencias/' )
,(u'Gente' , index + u'gente/' )
,(u'Obituarios' , index + u'obituarios/' )
,(u'Deportes' , index + u'deportes/' )
,(u'Pantallas' , index + u'radioytv/' )
,(u'Ultima' , index + u'ultima/' )
,(u'Educacion' , index + u'educacion/' )
,(u'Saludo' , index + u'salud/' )
,(u'Ciberpais' , index + u'ciberpais/' )
,(u'EP3' , index + u'ep3/' )
,(u'Cine' , index + u'cine/' )
,(u'Babelia' , index + u'babelia/' )
,(u'El viajero' , index + u'viajero/' )
,(u'Negocios' , index + u'negocios/' )
,(u'Domingo' , index + u'domingo/' )
,(u'El Pais semanal' , index + u'eps/' )
,(u'Quadern Catalunya' , index + u'quadern-catalunya/' )
]
keep_only_tags=[dict(attrs={'class':['cabecera_noticia','contenido_noticia']})]
remove_attributes=['width','height']
remove_tags=[dict(name='link')]
def parse_index(self):
totalfeeds = []
lfeeds = self.get_feeds()
for feedobj in lfeeds:
feedtitle, feedurl = feedobj
self.report_progress(0, _('Fetching feed')+' %s...'%(feedtitle if feedtitle else feedurl))
articles = []
soup = self.index_to_soup(feedurl)
for item in soup.findAll('a',attrs={'class':['g19r003','g19i003','g17r003','g17i003']}):
url = 'http://www.elpais.com' + item['href'].rpartition('/')[0]
title = self.tag_to_string(item)
date = strftime(self.timefmt)
articles.append({
'title' :title
,'date' :date
,'url' :url
,'description':''
})
totalfeeds.append((feedtitle, articles))
return totalfeeds
def print_version(self, url):
return url + '?print=1'

View File

@ -4,29 +4,27 @@ from calibre import __appname__
class GoogleReader(BasicNewsRecipe): class GoogleReader(BasicNewsRecipe):
title = 'Google Reader' title = 'Google Reader'
description = 'This recipe downloads feeds you have tagged from your Google Reader account.' description = 'This recipe fetches from your Google Reader account unread Starred items and unread Feeds you have placed in a folder via the manage subscriptions feature.'
needs_subscription = True needs_subscription = True
__author__ = 'davec' __author__ = 'davec, rollercoaster, Starson17'
base_url = 'http://www.google.com/reader/atom/' base_url = 'http://www.google.com/reader/atom/'
max_articles_per_feed = 50 oldest_article = 365
max_articles_per_feed = 250
get_options = '?n=%d&xt=user/-/state/com.google/read' % max_articles_per_feed get_options = '?n=%d&xt=user/-/state/com.google/read' % max_articles_per_feed
use_embedded_content = True use_embedded_content = True
def get_browser(self): def get_browser(self):
br = BasicNewsRecipe.get_browser() br = BasicNewsRecipe.get_browser(self)
if self.username is not None and self.password is not None: if self.username is not None and self.password is not None:
request = urllib.urlencode([('Email', self.username), ('Passwd', self.password), request = urllib.urlencode([('Email', self.username), ('Passwd', self.password),
('service', 'reader'), ('source', __appname__)]) ('service', 'reader'), ('accountType', 'HOSTED_OR_GOOGLE'), ('source', __appname__)])
response = br.open('https://www.google.com/accounts/ClientLogin', request) response = br.open('https://www.google.com/accounts/ClientLogin', request)
sid = re.search('SID=(\S*)', response.read()).group(1) auth = re.search('Auth=(\S*)', response.read()).group(1)
cookies = mechanize.CookieJar() cookies = mechanize.CookieJar()
br = mechanize.build_opener(mechanize.HTTPCookieProcessor(cookies)) br = mechanize.build_opener(mechanize.HTTPCookieProcessor(cookies))
cookies.set_cookie(mechanize.Cookie(None, 'SID', sid, None, False, '.google.com', True, True, '/', True, False, None, True, '', '', None)) br.addheaders = [('Authorization', 'GoogleLogin auth='+auth)]
return br return br
def get_feeds(self): def get_feeds(self):
feeds = [] feeds = []
soup = self.index_to_soup('http://www.google.com/reader/api/0/tag/list') soup = self.index_to_soup('http://www.google.com/reader/api/0/tag/list')

View File

@ -3,10 +3,10 @@ from calibre.web.feeds.recipes import BasicNewsRecipe
from calibre import __appname__ from calibre import __appname__
class GoogleReaderUber(BasicNewsRecipe): class GoogleReaderUber(BasicNewsRecipe):
title = 'Google Reader Uber' title = 'Google Reader uber'
description = 'This recipe downloads all unread feedsfrom your Google Reader account.' description = 'Fetches all feeds from your Google Reader account including the uncategorized items.'
needs_subscription = True needs_subscription = True
__author__ = 'rollercoaster, davec' __author__ = 'davec, rollercoaster, Starson17'
base_url = 'http://www.google.com/reader/atom/' base_url = 'http://www.google.com/reader/atom/'
oldest_article = 365 oldest_article = 365
max_articles_per_feed = 250 max_articles_per_feed = 250
@ -14,20 +14,17 @@ class GoogleReaderUber(BasicNewsRecipe):
use_embedded_content = True use_embedded_content = True
def get_browser(self): def get_browser(self):
br = BasicNewsRecipe.get_browser() br = BasicNewsRecipe.get_browser(self)
if self.username is not None and self.password is not None: if self.username is not None and self.password is not None:
request = urllib.urlencode([('Email', self.username), ('Passwd', self.password), request = urllib.urlencode([('Email', self.username), ('Passwd', self.password),
('service', 'reader'), ('source', __appname__)]) ('service', 'reader'), ('accountType', 'HOSTED_OR_GOOGLE'), ('source', __appname__)])
response = br.open('https://www.google.com/accounts/ClientLogin', request) response = br.open('https://www.google.com/accounts/ClientLogin', request)
sid = re.search('SID=(\S*)', response.read()).group(1) auth = re.search('Auth=(\S*)', response.read()).group(1)
cookies = mechanize.CookieJar() cookies = mechanize.CookieJar()
br = mechanize.build_opener(mechanize.HTTPCookieProcessor(cookies)) br = mechanize.build_opener(mechanize.HTTPCookieProcessor(cookies))
cookies.set_cookie(mechanize.Cookie(None, 'SID', sid, None, False, '.google.com', True, True, '/', True, False, None, True, '', '', None)) br.addheaders = [('Authorization', 'GoogleLogin auth='+auth)]
return br return br
def get_feeds(self): def get_feeds(self):
feeds = [] feeds = []
soup = self.index_to_soup('http://www.google.com/reader/api/0/tag/list') soup = self.index_to_soup('http://www.google.com/reader/api/0/tag/list')

View File

@ -0,0 +1,34 @@
from calibre.web.feeds.news import BasicNewsRecipe
class AdvancedUserRecipe1278773519(BasicNewsRecipe):
title = u'Waco Tribune Herald'
__author__ = 'rty'
pubisher = 'A Robinson Media Company'
description = 'Waco, Texas, Newspaper'
category = 'News, Texas, Waco'
oldest_article = 7
max_articles_per_feed = 100
feeds = [
(u'News', u'http://www.wacotrib.com/news/index.rss2'),
(u'Sports', u'http://www.wacotrib.com/sports/index.rss2'),
(u'AccessWaco', u'http://www.wacotrib.com/accesswaco/index.rss2'),
(u'Opinions', u'http://www.wacotrib.com/opinion/index.rss2')
]
remove_javascript = True
use_embedded_content = False
no_stylesheets = True
language = 'en'
encoding = 'utf-8'
conversion_options = {'linearize_tables':True}
masthead_url = 'http://media.wacotrib.com/designimages/wacotrib_logo.jpg'
keep_only_tags = [
dict(name='div', attrs={'class':'twoColumn left'}),
]
remove_tags = [
dict(name='div', attrs={'class':'right blueLinks'}),
]
remove_tags_after = [
dict(name='div', attrs={'class':'dottedRule'}),
]

View File

@ -30,7 +30,8 @@ class ANDROID(USBMS):
0x18d1 : { 0x4e11 : [0x0100, 0x226], 0x4e12: [0x0100, 0x226]}, 0x18d1 : { 0x4e11 : [0x0100, 0x226], 0x4e12: [0x0100, 0x226]},
# Samsung # Samsung
0x04e8 : { 0x681d : [0x0222, 0x0400], 0x681c : [0x0222, 0x0224]}, 0x04e8 : { 0x681d : [0x0222, 0x0400],
0x681c : [0x0222, 0x0224, 0x0400]},
# Acer # Acer
0x502 : { 0x3203 : [0x0100]}, 0x502 : { 0x3203 : [0x0100]},
@ -70,6 +71,16 @@ class ANDROID(USBMS):
dirs = [x.strip() for x in dirs.split(',')] dirs = [x.strip() for x in dirs.split(',')]
self.EBOOK_DIR_MAIN = dirs self.EBOOK_DIR_MAIN = dirs
def get_main_ebook_dir(self, for_upload=False):
dirs = self.EBOOK_DIR_MAIN
if not for_upload:
def aldiko_tweak(x):
return 'eBooks' if x == 'eBooks/import' else x
if isinstance(dirs, basestring):
dirs = [dirs]
dirs = list(map(aldiko_tweak, dirs))
return dirs
class S60(USBMS): class S60(USBMS):
name = 'S60 driver' name = 'S60 driver'

View File

@ -2586,14 +2586,20 @@ class ITUNES(DriverBase):
if metadata.series and self.settings().read_metadata: if metadata.series and self.settings().read_metadata:
if DEBUG: if DEBUG:
self.log.info(" using Series name as Genre") self.log.info(" using Series name as Genre")
# Format the index as a sort key
index = metadata.series_index
integer = int(index)
fraction = index-integer
series_index = '%04d%s' % (integer, str('%0.4f' % fraction).lstrip('0'))
if lb_added: if lb_added:
lb_added.sort_name.set("%s %04f" % (metadata.series, metadata.series_index)) lb_added.sort_name.set("%s %s" % (metadata.series, series_index))
lb_added.genre.set(metadata.series) lb_added.genre.set(metadata.series)
lb_added.episode_ID.set(metadata.series) lb_added.episode_ID.set(metadata.series)
lb_added.episode_number.set(metadata.series_index) lb_added.episode_number.set(metadata.series_index)
if db_added: if db_added:
db_added.sort_name.set("%s %04f" % (metadata.series, metadata.series_index)) db_added.sort_name.set("%s %s" % (metadata.series, series_index))
db_added.genre.set(metadata.series) db_added.genre.set(metadata.series)
db_added.episode_ID.set(metadata.series) db_added.episode_ID.set(metadata.series)
db_added.episode_number.set(metadata.series_index) db_added.episode_number.set(metadata.series_index)
@ -2658,8 +2664,13 @@ class ITUNES(DriverBase):
if metadata.series and self.settings().read_metadata: if metadata.series and self.settings().read_metadata:
if DEBUG: if DEBUG:
self.log.info(" using Series name as Genre") self.log.info(" using Series name as Genre")
# Format the index as a sort key
index = metadata.series_index
integer = int(index)
fraction = index-integer
series_index = '%04d%%s' % (integer, str('%0.4f' % fraction).lstrip('0'))
if lb_added: if lb_added:
lb_added.SortName = "%s %04f" % (metadata.series, metadata.series_index) lb_added.SortName = "%s %s" % (metadata.series, series_index)
lb_added.Genre = metadata.series lb_added.Genre = metadata.series
lb_added.EpisodeID = metadata.series lb_added.EpisodeID = metadata.series
try: try:
@ -2667,7 +2678,7 @@ class ITUNES(DriverBase):
except: except:
pass pass
if db_added: if db_added:
db_added.SortName = "%s %04f" % (metadata.series, metadata.series_index) db_added.SortName = "%s %s" % (metadata.series, series_index)
db_added.Genre = metadata.series db_added.Genre = metadata.series
db_added.EpisodeID = metadata.series db_added.EpisodeID = metadata.series
try: try:

View File

@ -10,10 +10,10 @@ from base64 import b64decode
from uuid import uuid4 from uuid import uuid4
from lxml import etree from lxml import etree
from calibre import prints, guess_type from calibre import prints, guess_type, isbytestring
from calibre.devices.errors import DeviceError from calibre.devices.errors import DeviceError
from calibre.devices.usbms.driver import debug_print from calibre.devices.usbms.driver import debug_print
from calibre.constants import DEBUG from calibre.constants import DEBUG, preferred_encoding
from calibre.ebooks.chardet import xml_to_unicode from calibre.ebooks.chardet import xml_to_unicode
from calibre.ebooks.metadata import authors_to_string, title_sort from calibre.ebooks.metadata import authors_to_string, title_sort
@ -473,6 +473,13 @@ class XMLCache(object):
# if the case of a tie, and hope it is right. # if the case of a tie, and hope it is right.
timestamp = os.path.getmtime(path) timestamp = os.path.getmtime(path)
rec_date = record.get('date', None) rec_date = record.get('date', None)
def clean(x):
if isbytestring(x):
x = x.decode(preferred_encoding, 'replace')
x.replace(u'\0', '')
return x
if not getattr(book, '_new_book', False): # book is not new if not getattr(book, '_new_book', False): # book is not new
if strftime(timestamp, zone=time.gmtime) == rec_date: if strftime(timestamp, zone=time.gmtime) == rec_date:
gtz_count += 1 gtz_count += 1
@ -486,19 +493,19 @@ class XMLCache(object):
tz = time.gmtime tz = time.gmtime
debug_print("Using GMT TZ for new book", book.lpath) debug_print("Using GMT TZ for new book", book.lpath)
date = strftime(timestamp, zone=tz) date = strftime(timestamp, zone=tz)
record.set('date', date) record.set('date', clean(date))
record.set('size', str(os.stat(path).st_size)) record.set('size', clean(str(os.stat(path).st_size)))
title = book.title if book.title else _('Unknown') title = book.title if book.title else _('Unknown')
record.set('title', title) record.set('title', clean(title))
ts = book.title_sort ts = book.title_sort
if not ts: if not ts:
ts = title_sort(title) ts = title_sort(title)
record.set('titleSorter', ts) record.set('titleSorter', clean(ts))
if self.use_author_sort and book.author_sort is not None: if self.use_author_sort and book.author_sort is not None:
record.set('author', book.author_sort) record.set('author', clean(book.author_sort))
else: else:
record.set('author', authors_to_string(book.authors)) record.set('author', clean(authors_to_string(book.authors)))
ext = os.path.splitext(path)[1] ext = os.path.splitext(path)[1]
if ext: if ext:
ext = ext[1:].lower() ext = ext[1:].lower()
@ -506,7 +513,7 @@ class XMLCache(object):
if mime is None: if mime is None:
mime = guess_type('a.'+ext)[0] mime = guess_type('a.'+ext)[0]
if mime is not None: if mime is not None:
record.set('mime', mime) record.set('mime', clean(mime))
if 'sourceid' not in record.attrib: if 'sourceid' not in record.attrib:
record.set('sourceid', '1') record.set('sourceid', '1')
if 'id' not in record.attrib: if 'id' not in record.attrib:

View File

@ -98,6 +98,9 @@ class LinuxScanner(object):
def __call__(self): def __call__(self):
ans = set([]) ans = set([])
if not self.ok:
raise RuntimeError('DeviceScanner requires the /sys filesystem to work.')
for x in os.listdir(self.base): for x in os.listdir(self.base):
base = os.path.join(self.base, x) base = os.path.join(self.base, x)
ven = os.path.join(base, 'idVendor') ven = os.path.join(base, 'idVendor')
@ -145,8 +148,6 @@ class DeviceScanner(object):
def __init__(self, *args): def __init__(self, *args):
if isosx and osx_scanner is None: if isosx and osx_scanner is None:
raise RuntimeError('The Python extension usbobserver must be available on OS X.') raise RuntimeError('The Python extension usbobserver must be available on OS X.')
if islinux and not linux_scanner.ok:
raise RuntimeError('DeviceScanner requires the /sys filesystem to work.')
self.scanner = win_scanner if iswindows else osx_scanner if isosx else linux_scanner self.scanner = win_scanner if iswindows else osx_scanner if isosx else linux_scanner
self.devices = [] self.devices = []

View File

@ -732,7 +732,7 @@ class Device(DeviceConfig, DevicePlugin):
traceback.print_exc() traceback.print_exc()
self._main_prefix = self._card_a_prefix = self._card_b_prefix = None self._main_prefix = self._card_a_prefix = self._card_b_prefix = None
def get_main_ebook_dir(self): def get_main_ebook_dir(self, for_upload=False):
return self.EBOOK_DIR_MAIN return self.EBOOK_DIR_MAIN
def _sanity_check(self, on_card, files): def _sanity_check(self, on_card, files):
@ -750,7 +750,7 @@ class Device(DeviceConfig, DevicePlugin):
path = os.path.join(self._card_b_prefix, path = os.path.join(self._card_b_prefix,
*(self.EBOOK_DIR_CARD_B.split('/'))) *(self.EBOOK_DIR_CARD_B.split('/')))
else: else:
candidates = self.get_main_ebook_dir() candidates = self.get_main_ebook_dir(for_upload=True)
if isinstance(candidates, basestring): if isinstance(candidates, basestring):
candidates = [candidates] candidates = [candidates]
candidates = [ candidates = [

View File

@ -28,7 +28,11 @@
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QComboBox" name="opt_chapter_mark"/> <widget class="QComboBox" name="opt_chapter_mark">
<property name="minimumContentsLength">
<number>20</number>
</property>
</widget>
</item> </item>
<item row="2" column="0"> <item row="2" column="0">
<widget class="QCheckBox" name="opt_remove_first_image"> <widget class="QCheckBox" name="opt_remove_first_image">

View File

@ -43,6 +43,15 @@
<height>0</height> <height>0</height>
</size> </size>
</property> </property>
<property name="maximumSize">
<size>
<width>500</width>
<height>16777215</height>
</size>
</property>
<property name="minimumContentsLength">
<number>30</number>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>

View File

@ -10,9 +10,10 @@ from functools import partial
from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateEdit, \ from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateEdit, \
QDate, QGroupBox, QVBoxLayout, QPlainTextEdit, QSizePolicy, \ QDate, QGroupBox, QVBoxLayout, QPlainTextEdit, QSizePolicy, \
QSpacerItem, QIcon, QCheckBox, QWidget, QHBoxLayout, SIGNAL QSpacerItem, QIcon, QCheckBox, QWidget, QHBoxLayout, SIGNAL, \
QPushButton
from calibre.utils.date import qt_to_dt from calibre.utils.date import qt_to_dt, now
from calibre.gui2.widgets import TagsLineEdit, EnComboBox from calibre.gui2.widgets import TagsLineEdit, EnComboBox
from calibre.gui2 import UNDEFINED_QDATE from calibre.gui2 import UNDEFINED_QDATE
from calibre.utils.config import tweaks from calibre.utils.config import tweaks
@ -132,20 +133,30 @@ class DateEdit(QDateEdit):
def focusInEvent(self, x): def focusInEvent(self, x):
self.setSpecialValueText('') self.setSpecialValueText('')
QDateEdit.focusInEvent(self, x)
def focusOutEvent(self, x): def focusOutEvent(self, x):
self.setSpecialValueText(_('Undefined')) self.setSpecialValueText(_('Undefined'))
QDateEdit.focusOutEvent(self, x)
def set_to_today(self):
self.setDate(now())
class DateTime(Base): class DateTime(Base):
def setup_ui(self, parent): def setup_ui(self, parent):
self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent), cm = self.col_metadata
DateEdit(parent)] self.widgets = [QLabel('&'+cm['name']+':', parent), DateEdit(parent),
QLabel(''), QPushButton(_('Set \'%s\' to today')%cm['name'], parent)]
w = self.widgets[1] w = self.widgets[1]
w.setDisplayFormat('dd MMM yyyy') format = cm['display'].get('date_format','')
if not format:
format = 'dd MMM yyyy'
w.setDisplayFormat(format)
w.setCalendarPopup(True) w.setCalendarPopup(True)
w.setMinimumDate(UNDEFINED_QDATE) w.setMinimumDate(UNDEFINED_QDATE)
w.setSpecialValueText(_('Undefined')) w.setSpecialValueText(_('Undefined'))
self.widgets[3].clicked.connect(w.set_to_today)
def setter(self, val): def setter(self, val):
if val is None: if val is None:

View File

@ -765,6 +765,7 @@ class DeviceMixin(object): # {{{
self.book_details.reset_info() self.book_details.reset_info()
self.location_view.setCurrentIndex(self.location_view.model().index(0)) self.location_view.setCurrentIndex(self.location_view.model().index(0))
self.refresh_ondevice_info (device_connected = False) self.refresh_ondevice_info (device_connected = False)
self.tool_bar.device_status_changed(bool(connected))
def info_read(self, job): def info_read(self, job):
''' '''

View File

@ -334,7 +334,6 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
def __init__(self, parent, library_view, server=None): def __init__(self, parent, library_view, server=None):
ResizableDialog.__init__(self, parent) ResizableDialog.__init__(self, parent)
self.ICON_SIZES = {0:QSize(48, 48), 1:QSize(32,32), 2:QSize(24,24)}
self._category_model = CategoryModel() self._category_model = CategoryModel()
self.category_view.currentChanged = self.category_current_changed self.category_view.currentChanged = self.category_current_changed
@ -389,10 +388,6 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
self.add_custcol_button.clicked.connect(self.add_custcol) self.add_custcol_button.clicked.connect(self.add_custcol)
self.edit_custcol_button.clicked.connect(self.edit_custcol) self.edit_custcol_button.clicked.connect(self.edit_custcol)
icons = config['toolbar_icon_size']
self.toolbar_button_size.setCurrentIndex(0 if icons == self.ICON_SIZES[0] else 1 if icons == self.ICON_SIZES[1] else 2)
self.show_toolbar_text.setChecked(config['show_text_in_toolbar'])
output_formats = sorted(available_output_formats()) output_formats = sorted(available_output_formats())
output_formats.remove('oeb') output_formats.remove('oeb')
for f in output_formats: for f in output_formats:
@ -845,8 +840,6 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
must_restart = self.apply_custom_column_changes() must_restart = self.apply_custom_column_changes()
config['toolbar_icon_size'] = self.ICON_SIZES[self.toolbar_button_size.currentIndex()]
config['show_text_in_toolbar'] = bool(self.show_toolbar_text.isChecked())
config['separate_cover_flow'] = bool(self.separate_cover_flow.isChecked()) config['separate_cover_flow'] = bool(self.separate_cover_flow.isChecked())
config['disable_tray_notification'] = not self.systray_notifications.isChecked() config['disable_tray_notification'] = not self.systray_notifications.isChecked()
p = {0:'normal', 1:'high', 2:'low'}[self.priority.currentIndex()] p = {0:'normal', 1:'high', 2:'low'}[self.priority.currentIndex()]

View File

@ -422,54 +422,6 @@
</layout> </layout>
</item> </item>
<item row="10" column="0" colspan="2"> <item row="10" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Toolbar</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QComboBox" name="toolbar_button_size">
<item>
<property name="text">
<string>Large</string>
</property>
</item>
<item>
<property name="text">
<string>Medium</string>
</property>
</item>
<item>
<property name="text">
<string>Small</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>&amp;Button size in toolbar</string>
</property>
<property name="buddy">
<cstring>toolbar_button_size</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="show_toolbar_text">
<property name="text">
<string>Show &amp;text in toolbar buttons</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="11" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_7"> <layout class="QHBoxLayout" name="horizontalLayout_7">
<item> <item>
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="groupBox">

View File

@ -176,12 +176,6 @@ class ToolbarMixin(object): # {{{
def show_help(self, *args): def show_help(self, *args):
open_url(QUrl('http://calibre-ebook.com/user_manual')) open_url(QUrl('http://calibre-ebook.com/user_manual'))
def read_toolbar_settings(self):
self.tool_bar.setIconSize(config['toolbar_icon_size'])
self.tool_bar.setToolButtonStyle(
Qt.ToolButtonTextUnderIcon if \
config['show_text_in_toolbar'] else \
Qt.ToolButtonIconOnly)
# }}} # }}}

View File

@ -5,6 +5,8 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
from operator import attrgetter
from PyQt4.Qt import QIcon, Qt, QWidget, QAction, QToolBar, QSize, QVariant, \ from PyQt4.Qt import QIcon, Qt, QWidget, QAction, QToolBar, QSize, QVariant, \
QAbstractListModel, QFont, QApplication, QPalette, pyqtSignal, QToolButton, \ QAbstractListModel, QFont, QApplication, QPalette, pyqtSignal, QToolButton, \
QModelIndex, QListView, QAbstractButton, QPainter, QPixmap, QColor, \ QModelIndex, QListView, QAbstractButton, QPainter, QPixmap, QColor, \
@ -13,41 +15,11 @@ from PyQt4.Qt import QIcon, Qt, QWidget, QAction, QToolBar, QSize, QVariant, \
from calibre.constants import __appname__, filesystem_encoding from calibre.constants import __appname__, filesystem_encoding
from calibre.gui2.search_box import SearchBox2, SavedSearchBox from calibre.gui2.search_box import SearchBox2, SavedSearchBox
from calibre.gui2.throbber import ThrobbingButton from calibre.gui2.throbber import ThrobbingButton
from calibre.gui2 import NONE from calibre.gui2 import NONE, config
from calibre.gui2.widgets import ComboBoxWithHelp from calibre.gui2.widgets import ComboBoxWithHelp
from calibre import human_readable from calibre import human_readable
class ToolBar(QToolBar): # {{{ ICON_SIZE = 48
def __init__(self, parent=None):
QToolBar.__init__(self, parent)
self.setContextMenuPolicy(Qt.PreventContextMenu)
self.setMovable(False)
self.setFloatable(False)
self.setOrientation(Qt.Horizontal)
self.setAllowedAreas(Qt.TopToolBarArea|Qt.BottomToolBarArea)
self.setIconSize(QSize(48, 48))
self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
def add_actions(self, *args):
self.left_space = QWidget(self)
self.left_space.setSizePolicy(QSizePolicy.Expanding,
QSizePolicy.Minimum)
self.addWidget(self.left_space)
for action in args:
if action is None:
self.addSeparator()
else:
self.addAction(action)
self.right_space = QWidget(self)
self.right_space.setSizePolicy(QSizePolicy.Expanding,
QSizePolicy.Minimum)
self.addWidget(self.right_space)
def contextMenuEvent(self, *args):
pass
# }}}
# Location View {{{ # Location View {{{
@ -191,14 +163,15 @@ class LocationView(QListView):
self.setTabKeyNavigation(True) self.setTabKeyNavigation(True)
self.setProperty("showDropIndicator", True) self.setProperty("showDropIndicator", True)
self.setSelectionMode(self.SingleSelection) self.setSelectionMode(self.SingleSelection)
self.setIconSize(QSize(40, 40)) self.setIconSize(QSize(ICON_SIZE, ICON_SIZE))
self.setMovement(self.Static) self.setMovement(self.Static)
self.setFlow(self.LeftToRight) self.setFlow(self.LeftToRight)
self.setGridSize(QSize(175, 90)) self.setGridSize(QSize(175, ICON_SIZE))
self.setViewMode(self.ListMode) self.setViewMode(self.ListMode)
self.setWordWrap(True) self.setWordWrap(True)
self.setObjectName("location_view") self.setObjectName("location_view")
self.setMaximumHeight(74) self.setMaximumSize(QSize(600, ICON_SIZE+16))
self.setMinimumWidth(400)
def eject_clicked(self, *args): def eject_clicked(self, *args):
self.unmount_device.emit() self.unmount_device.emit()
@ -207,6 +180,10 @@ class LocationView(QListView):
self.model().count = new_count self.model().count = new_count
self.model().reset() self.model().reset()
@property
def book_count(self):
return self.model().count
def current_changed(self, current, previous): def current_changed(self, current, previous):
if current.isValid(): if current.isValid():
i = current.row() i = current.row()
@ -248,12 +225,15 @@ class EjectButton(QAbstractButton):
def __init__(self, parent): def __init__(self, parent):
QAbstractButton.__init__(self, parent) QAbstractButton.__init__(self, parent)
self.mouse_over = False self.mouse_over = False
self.setMouseTracking(True)
def enterEvent(self, event): def enterEvent(self, event):
self.mouse_over = True self.mouse_over = True
QAbstractButton.enterEvent(self, event)
def leaveEvent(self, event): def leaveEvent(self, event):
self.mouse_over = False self.mouse_over = False
QAbstractButton.leaveEvent(self, event)
def paintEvent(self, event): def paintEvent(self, event):
painter = QPainter(self) painter = QPainter(self)
@ -344,33 +324,84 @@ class SearchBar(QWidget): # {{{
# }}} # }}}
class LocationBar(ToolBar): # {{{ class ToolBar(QToolBar): # {{{
def __init__(self, actions, donate, location_view, parent=None): def __init__(self, actions, donate, location_view, parent=None):
ToolBar.__init__(self, parent) QToolBar.__init__(self, parent)
self.setContextMenuPolicy(Qt.PreventContextMenu)
for ac in actions: self.setMovable(False)
self.addAction(ac) self.setFloatable(False)
self.setOrientation(Qt.Horizontal)
self.addWidget(location_view) self.setAllowedAreas(Qt.TopToolBarArea|Qt.BottomToolBarArea)
self.w = QWidget() self.setIconSize(QSize(ICON_SIZE, ICON_SIZE))
self.w.setLayout(QVBoxLayout())
self.w.layout().addWidget(donate)
donate.setAutoRaise(True)
donate.setCursor(Qt.PointingHandCursor)
self.addWidget(self.w)
self.setIconSize(QSize(50, 50))
self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
def button_for_action(self, ac): self.showing_device = False
b = QToolButton(self) self.all_actions = actions
b.setDefaultAction(ac) self.donate = donate
for x in ('ToolTip', 'StatusTip', 'WhatsThis'): self.location_view = location_view
getattr(b, 'set'+x)(b.text()) self.d_widget = QWidget()
self.d_widget.setLayout(QVBoxLayout())
self.d_widget.layout().addWidget(donate)
donate.setAutoRaise(True)
donate.setCursor(Qt.PointingHandCursor)
self.build_bar()
def contextMenuEvent(self, *args):
pass
def device_status_changed(self, connected):
self.showing_device = connected
self.build_bar()
def build_bar(self):
order_field = 'device' if self.showing_device else 'normal'
o = attrgetter(order_field+'_order')
sepvals = [2] if self.showing_device else [1]
sepvals += [3]
actions = [x for x in self.all_actions if o(x) > -1]
actions.sort(cmp=lambda x,y : cmp(o(x), o(y)))
self.clear()
for x in actions:
self.addAction(x)
ch = self.widgetForAction(x)
ch.setCursor(Qt.PointingHandCursor)
ch.setAutoRaise(True)
if x.action_name == 'choose_library':
self.location_action = self.addWidget(self.location_view)
self.choose_action = x
if config['show_donate_button']:
self.addWidget(self.d_widget)
if x.action_name not in ('choose_library', 'help'):
ch.setPopupMode(ch.MenuButtonPopup)
for x in actions:
if x.separator_before in sepvals:
self.insertSeparator(x)
self.location_action.setVisible(self.showing_device)
self.choose_action.setVisible(not self.showing_device)
def count_changed(self, new_count):
text = _('%d books')%new_count
a = self.choose_action
a.setText(text)
def resizeEvent(self, ev):
style = Qt.ToolButtonTextUnderIcon
if self.size().width() < 1260:
style = Qt.ToolButtonIconOnly
self.setToolButtonStyle(style)
QToolBar.resizeEvent(self, ev)
return b
# }}} # }}}
class Action(QAction):
pass
class MainWindowMixin(object): class MainWindowMixin(object):
def __init__(self): def __init__(self):
@ -385,12 +416,19 @@ class MainWindowMixin(object):
self.centralwidget.setLayout(self._central_widget_layout) self.centralwidget.setLayout(self._central_widget_layout)
self.resize(1012, 740) self.resize(1012, 740)
self.donate_button = ThrobbingButton(self.centralwidget) self.donate_button = ThrobbingButton(self.centralwidget)
self.donate_button.set_normal_icon_size(64, 64) self.donate_button.set_normal_icon_size(ICON_SIZE, ICON_SIZE)
# Actions {{{ # Actions {{{
def ac(name, text, icon, shortcut=None, tooltip=None): all_actions = []
action = QAction(QIcon(I(icon)), text, self)
def ac(normal_order, device_order, separator_before,
name, text, icon, shortcut=None, tooltip=None):
action = Action(QIcon(I(icon)), text, self)
action.normal_order = normal_order
action.device_order = device_order
action.separator_before = separator_before
action.action_name = name
text = tooltip if tooltip else text text = tooltip if tooltip else text
action.setToolTip(text) action.setToolTip(text)
action.setStatusTip(text) action.setStatusTip(text)
@ -400,56 +438,46 @@ class MainWindowMixin(object):
if shortcut: if shortcut:
action.setShortcut(shortcut) action.setShortcut(shortcut)
setattr(self, 'action_'+name, action) setattr(self, 'action_'+name, action)
all_actions.append(action)
ac('add', _('Add books'), 'add_book.svg', _('A')) ac(0, 7, 0, 'add', _('Add books'), 'add_book.svg', _('A'))
ac('del', _('Remove books'), 'trash.svg', _('Del')) ac(1, 1, 0, 'edit', _('Edit metadata'), 'edit_input.svg', _('E'))
ac('edit', _('Edit meta info'), 'edit_input.svg', _('E')) ac(2, 2, 3, 'convert', _('Convert books'), 'convert.svg', _('C'))
ac('merge', _('Merge book records'), 'merge_books.svg', _('M')) ac(3, 3, 0, 'view', _('View'), 'view.svg', _('V'))
ac('sync', _('Send to device'), 'sync.svg') ac(4, 4, 3, 'choose_library', _('%d books')%0, 'lt.png',
ac('save', _('Save to disk'), 'save.svg', _('S')) tooltip=_('Choose calibre library to work with'))
ac('news', _('Fetch news'), 'news.svg', _('F')) ac(5, 5, 3, 'news', _('Fetch news'), 'news.svg', _('F'))
ac('convert', _('Convert books'), 'convert.svg', _('C')) ac(6, 6, 0, 'save', _('Save to disk'), 'save.svg', _('S'))
ac('view', _('View'), 'view.svg', _('V')) ac(7, 0, 0, 'sync', _('Send to device'), 'sync.svg')
ac('open_containing_folder', _('Open containing folder'), ac(8, 8, 3, 'del', _('Remove books'), 'trash.svg', _('Del'))
ac(9, 9, 3, 'help', _('Help'), 'help.svg', _('F1'), _("Browse the calibre User Manual"))
ac(10, 10, 0, 'preferences', _('Preferences'), 'config.svg', _('Ctrl+P'))
ac(-1, -1, 0, 'merge', _('Merge book records'), 'merge_books.svg', _('M'))
ac(-1, -1, 0, 'open_containing_folder', _('Open containing folder'),
'document_open.svg') 'document_open.svg')
ac('show_book_details', _('Show book details'), ac(-1, -1, 0, 'show_book_details', _('Show book details'),
'dialog_information.svg') 'dialog_information.svg')
ac('books_by_same_author', _('Books by same author'), ac(-1, -1, 0, 'books_by_same_author', _('Books by same author'),
'user_profile.svg') 'user_profile.svg')
ac('books_in_this_series', _('Books in this series'), ac(-1, -1, 0, 'books_in_this_series', _('Books in this series'),
'books_in_series.svg') 'books_in_series.svg')
ac('books_by_this_publisher', _('Books by this publisher'), ac(-1, -1, 0, 'books_by_this_publisher', _('Books by this publisher'),
'publisher.png') 'publisher.png')
ac('books_with_the_same_tags', _('Books with the same tags'), ac(-1, -1, 0, 'books_with_the_same_tags', _('Books with the same tags'),
'tags.svg') 'tags.svg')
ac('preferences', _('Preferences'), 'config.svg', _('Ctrl+P'))
ac('help', _('Help'), 'help.svg', _('F1'), _("Browse the calibre User Manual"))
# }}} # }}}
self.tool_bar = ToolBar(self)
self.addToolBar(Qt.BottomToolBarArea, self.tool_bar)
self.tool_bar.add_actions(self.action_convert, self.action_view,
None, self.action_edit, None,
self.action_save, self.action_del,
None,
self.action_help, None, self.action_preferences)
self.location_view = LocationView(self.centralwidget) self.location_view = LocationView(self.centralwidget)
self.search_bar = SearchBar(self) self.search_bar = SearchBar(self)
self.location_bar = LocationBar([self.action_add, self.action_sync, self.tool_bar = ToolBar(all_actions, self.donate_button, self.location_view, self)
self.action_news], self.donate_button, self.location_view, self) self.addToolBar(Qt.TopToolBarArea, self.tool_bar)
self.addToolBar(Qt.TopToolBarArea, self.location_bar)
l = self.centralwidget.layout() l = self.centralwidget.layout()
l.addWidget(self.search_bar) l.addWidget(self.search_bar)
for ch in list(self.tool_bar.children()) + list(self.location_bar.children()):
if isinstance(ch, QToolButton):
ch.setCursor(Qt.PointingHandCursor)
ch.setAutoRaise(True)
if ch is not self.donate_button:
ch.setPopupMode(ch.MenuButtonPopup)
def read_toolbar_settings(self):
pass

View File

@ -96,7 +96,7 @@ class DateDelegate(QStyledItemDelegate): # {{{
def displayText(self, val, locale): def displayText(self, val, locale):
d = val.toDate() d = val.toDate()
if d == UNDEFINED_QDATE: if d <= UNDEFINED_QDATE:
return '' return ''
return format_date(d.toPyDate(), 'dd MMM yyyy') return format_date(d.toPyDate(), 'dd MMM yyyy')
@ -116,7 +116,7 @@ class PubDateDelegate(QStyledItemDelegate): # {{{
def displayText(self, val, locale): def displayText(self, val, locale):
d = val.toDate() d = val.toDate()
if d == UNDEFINED_QDATE: if d <= UNDEFINED_QDATE:
return '' return ''
format = tweaks['gui_pubdate_display_format'] format = tweaks['gui_pubdate_display_format']
if format is None: if format is None:
@ -194,7 +194,7 @@ class CcDateDelegate(QStyledItemDelegate): # {{{
def displayText(self, val, locale): def displayText(self, val, locale):
d = val.toDate() d = val.toDate()
if d == UNDEFINED_QDATE: if d <= UNDEFINED_QDATE:
return '' return ''
return format_date(d.toPyDate(), self.format) return format_date(d.toPyDate(), self.format)
@ -217,7 +217,7 @@ class CcDateDelegate(QStyledItemDelegate): # {{{
def setModelData(self, editor, model, index): def setModelData(self, editor, model, index):
val = editor.date() val = editor.date()
if val == UNDEFINED_QDATE: if val <= UNDEFINED_QDATE:
val = None val = None
model.setData(index, QVariant(val), Qt.EditRole) model.setData(index, QVariant(val), Qt.EditRole)

View File

@ -1216,7 +1216,9 @@ class DeviceBooksModel(BooksModel): # {{{
return done return done
def set_editable(self, editable): def set_editable(self, editable):
self.editable = editable # Cannot edit if metadata is sent on connect. Reason: changes will
# revert to what is in the library on next connect.
self.editable = editable and prefs['manage_device_metadata']!='on_connect'
def set_search_restriction(self, s): def set_search_restriction(self, s):
pass pass

View File

@ -13,6 +13,7 @@ class SearchRestrictionMixin(object):
self.search_restriction.setSizeAdjustPolicy(self.search_restriction.AdjustToMinimumContentsLengthWithIcon) self.search_restriction.setSizeAdjustPolicy(self.search_restriction.AdjustToMinimumContentsLengthWithIcon)
self.search_restriction.setMinimumContentsLength(10) self.search_restriction.setMinimumContentsLength(10)
self.search_restriction.setStatusTip(self.search_restriction.toolTip()) self.search_restriction.setStatusTip(self.search_restriction.toolTip())
self.search_count.setText(_("(all books)"))
''' '''
Adding and deleting books while restricted creates a complexity. When added, Adding and deleting books while restricted creates a complexity. When added,

View File

@ -167,8 +167,6 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, ToolbarMixin, # {{{
self.eject_action = self.system_tray_menu.addAction( self.eject_action = self.system_tray_menu.addAction(
QIcon(I('eject.svg')), _('&Eject connected device')) QIcon(I('eject.svg')), _('&Eject connected device'))
self.eject_action.setEnabled(False) self.eject_action.setEnabled(False)
if not config['show_donate_button']:
self.donate_button.setVisible(False)
self.addAction(self.quit_action) self.addAction(self.quit_action)
self.action_restart = QAction(_('&Restart'), self) self.action_restart = QAction(_('&Restart'), self)
self.addAction(self.action_restart) self.addAction(self.action_restart)
@ -220,8 +218,9 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, ToolbarMixin, # {{{
if self.system_tray_icon.isVisible() and opts.start_in_tray: if self.system_tray_icon.isVisible() and opts.start_in_tray:
self.hide_windows() self.hide_windows()
for t in (self.location_view, self.tool_bar):
self.library_view.model().count_changed_signal.connect \ self.library_view.model().count_changed_signal.connect \
(self.location_view.count_changed) (t.count_changed)
if not gprefs.get('quick_start_guide_added', False): if not gprefs.get('quick_start_guide_added', False):
from calibre.ebooks.metadata import MetaInformation from calibre.ebooks.metadata import MetaInformation
mi = MetaInformation(_('Calibre Quick Start Guide'), ['John Schember']) mi = MetaInformation(_('Calibre Quick Start Guide'), ['John Schember'])
@ -274,8 +273,6 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, ToolbarMixin, # {{{
SIGNAL('start_recipe_fetch(PyQt_PyObject)'), SIGNAL('start_recipe_fetch(PyQt_PyObject)'),
self.download_scheduled_recipe, Qt.QueuedConnection) self.download_scheduled_recipe, Qt.QueuedConnection)
self.location_view.setCurrentIndex(self.location_view.model().index(0))
self.keyboard_interrupt.connect(self.quit, type=Qt.QueuedConnection) self.keyboard_interrupt.connect(self.quit, type=Qt.QueuedConnection)
AddAction.__init__(self) AddAction.__init__(self)

View File

@ -209,13 +209,13 @@ class ResultCache(SearchQueryParser):
if query == 'false': if query == 'false':
for item in self._data: for item in self._data:
if item is None: continue if item is None: continue
if item[loc] is None or item[loc] == UNDEFINED_DATE: if item[loc] is None or item[loc] <= UNDEFINED_DATE:
matches.add(item[0]) matches.add(item[0])
return matches return matches
if query == 'true': if query == 'true':
for item in self._data: for item in self._data:
if item is None: continue if item is None: continue
if item[loc] is not None and item[loc] != UNDEFINED_DATE: if item[loc] is not None and item[loc] > UNDEFINED_DATE:
matches.add(item[0]) matches.add(item[0])
return matches return matches

View File

@ -3,7 +3,7 @@
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2010, Greg Riker <griker at hotmail.com>' __copyright__ = '2010, Greg Riker <griker at hotmail.com>'
import datetime, htmlentitydefs, os, re, shutil import datetime, htmlentitydefs, os, re, shutil, codecs
from collections import namedtuple from collections import namedtuple
from copy import deepcopy from copy import deepcopy
@ -96,17 +96,20 @@ class CSV_XML(CatalogPlugin):
fields = self.get_output_fields(opts) fields = self.get_output_fields(opts)
if self.fmt == 'csv': if self.fmt == 'csv':
outfile = open(path_to_output, 'w') outfile = codecs.open(path_to_output, 'w', 'utf8')
# Output the field headers # Output the field headers
outfile.write(u'%s\n' % u','.join(fields)) outfile.write(u'%s\n' % u','.join(fields))
# Output the entry fields # Output the entry fields
for entry in data: for entry in data:
outstr = '' outstr = []
for (x, field) in enumerate(fields): for field in fields:
item = entry[field] item = entry[field]
if field == 'formats': if item is None:
outstr.append('""')
continue
elif field == 'formats':
fmt_list = [] fmt_list = []
for format in item: for format in item:
fmt_list.append(format.rpartition('.')[2].lower()) fmt_list.append(format.rpartition('.')[2].lower())
@ -118,19 +121,13 @@ class CSV_XML(CatalogPlugin):
item = u'%s' % re.sub(r'[\D]', '', item) item = u'%s' % re.sub(r'[\D]', '', item)
elif field in ['pubdate', 'timestamp']: elif field in ['pubdate', 'timestamp']:
item = isoformat(item) item = isoformat(item)
elif field == 'comments':
item = item.replace(u'\r\n',u' ')
item = item.replace(u'\n',u' ')
#Format the line outstr.append(u'"%s"' % unicode(item).replace('"','""'))
if x < len(fields) - 1:
if item is not None: outfile.write(u','.join(outstr) + u'\n')
outstr += u'"%s",' % unicode(item).replace('"','""')
else:
outstr += '"",'
else:
if item is not None:
outstr += u'"%s"\n' % unicode(item).replace('"','""')
else:
outstr += '""\n'
outfile.write(outstr.encode('utf-8'))
outfile.close() outfile.close()
elif self.fmt == 'xml': elif self.fmt == 'xml':
@ -269,7 +266,6 @@ class BIBTEX(CatalogPlugin):
def run(self, path_to_output, opts, db, notification=DummyReporter()): def run(self, path_to_output, opts, db, notification=DummyReporter()):
import codecs
from types import StringType, UnicodeType from types import StringType, UnicodeType
from calibre.library.save_to_disk import preprocess_template from calibre.library.save_to_disk import preprocess_template