diff --git a/recipes/aachener_nachrichten.recipe b/recipes/aachener_nachrichten.recipe
new file mode 100644
index 0000000000..a2294fc472
--- /dev/null
+++ b/recipes/aachener_nachrichten.recipe
@@ -0,0 +1,42 @@
+from calibre.web.feeds.recipes import BasicNewsRecipe
+class AdvancedUserRecipe(BasicNewsRecipe):
+
+ title = u'Aachener Nachrichten'
+ __author__ = 'schuster'
+ oldest_article = 1
+ max_articles_per_feed = 100
+ use_embedded_content = False
+ language = 'de'
+ remove_javascript = True
+ cover_url = 'http://www.an-online.de/einwaage/images/an_logo.png'
+ masthead_url = 'http://www.an-online.de/einwaage/images/an_logo.png'
+ extra_css = '''
+ .fliesstext_detail:{margin-bottom:10%;}
+ .headline_1:{margin-bottom:25%;}
+ b{font-family:Arial,Helvetica,sans-serif; font-weight:200;font-size:large;}
+ a{font-family:Arial,Helvetica,sans-serif; font-weight:400;font-size:large;}
+ ll{font-family:Arial,Helvetica,sans-serif; font-weight:100;font-size:large;}
+ h4{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;}
+ img {min-width:300px; max-width:600px; min-height:300px; max-height:800px}
+ dd{font-family:Arial,Helvetica,sans-serif;font-size:large;}
+ body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
+ '''
+
+
+
+ keep_only_tags = [
+ dict(name='span', attrs={'class':['fliesstext_detail', 'headline_1', 'autor_detail']}),
+ dict(id=['header-logo'])
+ ]
+
+ feeds = [(u'Euregio', u'http://www.an-online.de/an/rss/Euregio.xml'),
+ (u'Aachen', u'http://www.an-online.de/an/rss/Aachen.xml'),
+ (u'Nordkreis', u'http://www.an-online.de/an/rss/Nordkreis.xml'),
+ (u'Düren', u'http://www.an-online.de/an/rss/Dueren.xml'),
+ (u'Eiffel', u'http://www.an-online.de/an/rss/Eifel.xml'),
+ (u'Eschweiler', u'http://www.an-online.de/an/rss/Eschweiler.xml'),
+ (u'Geilenkirchen', u'http://www.an-online.de/an/rss/Geilenkirchen.xml'),
+ (u'Heinsberg', u'http://www.an-online.de/an/rss/Heinsberg.xml'),
+ (u'Jülich', u'http://www.an-online.de/an/rss/Juelich.xml'),
+ (u'Stolberg', u'http://www.an-online.de/an/rss/Stolberg.xml'),
+ (u'Ratgebenr', u'http://www.an-online.de/an/rss/Ratgeber.xml')]
diff --git a/recipes/faznet.recipe b/recipes/faznet.recipe
index 01a46d43ba..50a66c59b8 100644
--- a/recipes/faznet.recipe
+++ b/recipes/faznet.recipe
@@ -3,10 +3,7 @@ class AdvancedUserRecipe1303841067(BasicNewsRecipe):
title = u'Faz.net'
__author__ = 'schuster'
- remove_tags = [dict(attrs={'class':['right', 'ArrowLinkRight', 'ModulVerlagsInfo', 'left', 'Head']}),
- dict(id=['BreadCrumbs', 'tstag', 'FazFooterPrint']),
- dict(name=['script', 'noscript', 'style'])]
- oldest_article = 2
+ oldest_article = 1
description = 'Frankfurter Allgemeine Zeitung'
max_articles_per_feed = 100
no_stylesheets = True
@@ -15,9 +12,9 @@ class AdvancedUserRecipe1303841067(BasicNewsRecipe):
remove_javascript = True
cover_url = 'http://www.faz.net/f30/Images/Logos/logo.gif'
- def print_version(self, url):
- return url.replace('.html', '~Afor~Eprint.html')
-
+ remove_tags = [dict(attrs={'class':['LinkBoxModulSmall', 'ModulLesermeinungenFooter', 'ModulArtikelServices', 'SocialMediaUnten', 'ArrowLinkRight', 'ModulVerlagsInfo', 'AdData', 'FazFooter', 'Date']}),
+ dict(id=['FAZNavHeader', 'FAZNavMain', 'RightColumn', 'FazFooter', 'BreadCrumbs', 'FAZNavSubMain', 'FAZImgEvent']),
+ dict(name=['jksrdt'])]
feeds = [(u'Politik', u'http://www.faz.net/s/RubA24ECD630CAE40E483841DB7D16F4211/Tpl~Epartner~SRss_.xml'),
diff --git a/recipes/frankfurter_rundschau.recipe b/recipes/frankfurter_rundschau.recipe
new file mode 100644
index 0000000000..3c3bb32ca3
--- /dev/null
+++ b/recipes/frankfurter_rundschau.recipe
@@ -0,0 +1,35 @@
+from calibre.web.feeds.recipes import BasicNewsRecipe
+class AdvancedUserRecipe(BasicNewsRecipe):
+
+ title = u'Frankfurter Rundschau'
+ __author__ = 'schuster'
+ oldest_article = 1
+ max_articles_per_feed = 100
+ no_stylesheets = True
+ use_embedded_content = False
+ language = 'de'
+ remove_javascript = True
+ cover_url = 'http://www.fr-online.de/image/view/-/1474018/data/823538/-/logo.png'
+ extra_css = '''
+ h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
+ h4{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;}
+ img {min-width:300px; max-width:600px; min-height:300px; max-height:800px}
+ p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
+ body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
+ '''
+
+ feeds = [(u'Startseite', u'http://www.fr-online.de/home/-/1472778/1472778/-/view/asFeed/-/index.xml'),
+ (u'Politik', u'http://www.fr-online.de/politik/-/1472596/1472596/-/view/asFeed/-/index.xml'),
+ (u'Meinungen', u'http://www.fr-online.de/politik/meinung/-/1472602/1472602/-/view/asFeed/-/index.xml'),
+ (u'Wirtschaft', u'http://www.fr-online.de/wirtschaft/-/1472780/1472780/-/view/asFeed/-/index.xml'),
+ (u'Sport', u'http://www.fr-online.de/sport/-/1472784/1472784/-/view/asFeed/-/index.xml'),
+ (u'Kultur', u'http://www.fr-online.de/kultur/-/1472786/1472786/-/view/asFeed/-/index.xml'),
+ (u'Panorama', u'http://www.fr-online.de/panorama/-/1472782/1472782/-/view/asFeed/-/index.xml'),
+ (u'Digital', u'http://www.fr-online.de/digital/-/1472406/1472406/-/view/asFeed/-/index.xml'),
+ (u'Wissenschaft', u'http://www.fr-online.de/wissenschaft/-/1472788/1472788/-/view/asFeed/-/index.xml')
+]
+
+
+ def print_version(self, url):
+ return url.replace('index.html', 'view/printVersion/-/index.html')
+
diff --git a/recipes/rheinische_post.recipe b/recipes/rheinische_post.recipe
new file mode 100644
index 0000000000..1d3efc710d
--- /dev/null
+++ b/recipes/rheinische_post.recipe
@@ -0,0 +1,55 @@
+from calibre.web.feeds.recipes import BasicNewsRecipe
+class AdvancedUserRecipe(BasicNewsRecipe):
+
+ title = u'RP-online'
+ __author__ = 'schuster'
+ oldest_article = 2
+ max_articles_per_feed = 100
+ no_stylesheets = True
+ use_embedded_content = False
+ language = 'de'
+ remove_javascript = True
+ masthead_url = 'http://www.die-zeitungen.de/uploads/pics/LOGO_RP_ONLINE_01.jpg'
+ cover_url = 'http://www.manroland.com/com/pressinfo_images/com/RheinischePost_Logo_300dpi.jpg'
+ extra_css = '''
+ h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
+ h4{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;}
+ img {min-width:300px; max-width:600px; min-height:300px; max-height:800px}
+ p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
+ body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
+ '''
+ remove_tags_before = dict(id='article_content')
+ remove_tags_after = dict(id='article_content')
+ remove_tags = [dict(attrs={'class':['goodies', 'left', 'right', 'clear-all', 'teaser anzeigenwerbung', 'lesermeinung', 'goodiebox', 'goodiebox 1', 'goodiebox 2', 'goodiebox 3', 'boxframe', 'link']}),
+ dict(id=['click_Fotos_link']),
+ dict(name=['script', 'noscript', 'style', '_top', 'click_Fotos_link'])]
+
+ feeds = [ (u'Top-News', u'http://www.ngz-online.de/app/feed/rss/topnews'),
+ (u'Politik', u'http://www.ngz-online.de/app/feed/rss/politik'),
+ (u'Wirtschaft', u'http://www.ngz-online.de/app/feed/rss/wirtschaft'),
+ (u'Panorama', u'http://www.ngz-online.de/app/feed/rss/panorama'),
+ (u'Sport', u'http://www.ngz-online.de/app/feed/rss/sport'),
+ (u'Tour de France', u'http://www.ngz-online.de/app/feed/rss/tourdefrance'),
+ (u'Fußball', u'http://www.ngz-online.de/app/feed/rss/fussball'),
+ (u'Fußball BuLi', u'http://www.ngz-online.de/app/feed/rss/bundesliga'),
+ (u'Formel 1', u'http://www.ngz-online.de/app/feed/rss/formel1'),
+ (u'US-Sport', u'http://www.ngz-online.de/app/feed/rss/us-sports'),
+ (u'Boxen', u'http://www.ngz-online.de/app/feed/rss/boxen'),
+ (u'Eishockey', u'http://www.ngz-online.de/app/feed/rss/eishockey'),
+ (u'Basketball', u'http://www.ngz-online.de/app/feed/rss/basketball'),
+ (u'Handball', u'http://www.ngz-online.de/app/feed/rss/handball'),
+ (u'Motorsport', u'http://www.ngz-online.de/app/feed/rss/motorsport'),
+ (u'Tennis', u'http://www.ngz-online.de/app/feed/rss/tennis'),
+ (u'Radsport', u'http://www.ngz-online.de/app/feed/rss/radsport'),
+ (u'Kultur', u'http://www.ngz-online.de/app/feed/rss/kultur'),
+ (u'Gesellschaft', u'http://www.ngz-online.de/app/feed/rss/gesellschaft'),
+ (u'Wissenschaft', u'http://www.ngz-online.de/app/feed/rss/wissen'),
+ (u'Gesundheit', u'http://www.ngz-online.de/app/feed/rss/gesundheit'),
+ (u'Digitale Welt', u'http://www.ngz-online.de/app/feed/rss/digitale'),
+ (u'Auto & Mobil', u'http://www.ngz-online.de/app/feed/rss/auto'),
+ (u'Reise & Welt', u'http://www.ngz-online.de/app/feed/rss/reise'),
+ (u'Beruf & Karriere', u'http://www.ngz-online.de/app/feed/rss/beruf'),
+ (u'Herzrasen', u'http://www.ngz-online.de/app/feed/rss/herzrasen'),
+ (u'About a Boy', u'http://www.ngz-online.de/app/feed/rss/about_a_boy'),
+
+]
diff --git a/resources/template-functions.json b/resources/template-functions.json
index 7656db4021..b0a2225dd4 100644
--- a/resources/template-functions.json
+++ b/resources/template-functions.json
@@ -1,19 +1,21 @@
{
+ "and": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n i = 0\n while i < len(args):\n if not args[i]:\n return ''\n i += 1\n return '1'\n",
"contains": "def evaluate(self, formatter, kwargs, mi, locals,\n val, test, value_if_present, value_if_not):\n if re.search(test, val):\n return value_if_present\n else:\n return value_if_not\n",
"divide": "def evaluate(self, formatter, kwargs, mi, locals, x, y):\n x = float(x if x else 0)\n y = float(y if y else 0)\n return unicode(x / y)\n",
"uppercase": "def evaluate(self, formatter, kwargs, mi, locals, val):\n return val.upper()\n",
"strcat": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n i = 0\n res = ''\n for i in range(0, len(args)):\n res += args[i]\n return res\n",
"in_list": "def evaluate(self, formatter, kwargs, mi, locals, val, sep, pat, fv, nfv):\n l = [v.strip() for v in val.split(sep) if v.strip()]\n for v in l:\n if re.search(pat, v):\n return fv\n return nfv\n",
- "substr": "def evaluate(self, formatter, kwargs, mi, locals, str_, start_, end_):\n return str_[int(start_): len(str_) if int(end_) == 0 else int(end_)]\n",
+ "multiply": "def evaluate(self, formatter, kwargs, mi, locals, x, y):\n x = float(x if x else 0)\n y = float(y if y else 0)\n return unicode(x * y)\n",
"ifempty": "def evaluate(self, formatter, kwargs, mi, locals, val, value_if_empty):\n if val:\n return val\n else:\n return value_if_empty\n",
"booksize": "def evaluate(self, formatter, kwargs, mi, locals):\n if mi.book_size is not None:\n try:\n return str(mi.book_size)\n except:\n pass\n return ''\n",
"select": "def evaluate(self, formatter, kwargs, mi, locals, val, key):\n if not val:\n return ''\n vals = [v.strip() for v in val.split(',')]\n for v in vals:\n if v.startswith(key+':'):\n return v[len(key)+1:]\n return ''\n",
+ "strcmp": "def evaluate(self, formatter, kwargs, mi, locals, x, y, lt, eq, gt):\n v = strcmp(x, y)\n if v < 0:\n return lt\n if v == 0:\n return eq\n return gt\n",
"first_non_empty": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n i = 0\n while i < len(args):\n if args[i]:\n return args[i]\n i += 1\n return ''\n",
- "field": "def evaluate(self, formatter, kwargs, mi, locals, name):\n return formatter.get_value(name, [], kwargs)\n",
+ "re": "def evaluate(self, formatter, kwargs, mi, locals, val, pattern, replacement):\n return re.sub(pattern, replacement, val)\n",
"subtract": "def evaluate(self, formatter, kwargs, mi, locals, x, y):\n x = float(x if x else 0)\n y = float(y if y else 0)\n return unicode(x - y)\n",
"list_item": "def evaluate(self, formatter, kwargs, mi, locals, val, index, sep):\n if not val:\n return ''\n index = int(index)\n val = val.split(sep)\n try:\n return val[index]\n except:\n return ''\n",
"shorten": "def evaluate(self, formatter, kwargs, mi, locals,\n val, leading, center_string, trailing):\n l = max(0, int(leading))\n t = max(0, int(trailing))\n if len(val) > l + len(center_string) + t:\n return val[0:l] + center_string + ('' if t == 0 else val[-t:])\n else:\n return val\n",
- "re": "def evaluate(self, formatter, kwargs, mi, locals, val, pattern, replacement):\n return re.sub(pattern, replacement, val)\n",
+ "field": "def evaluate(self, formatter, kwargs, mi, locals, name):\n return formatter.get_value(name, [], kwargs)\n",
"add": "def evaluate(self, formatter, kwargs, mi, locals, x, y):\n x = float(x if x else 0)\n y = float(y if y else 0)\n return unicode(x + y)\n",
"lookup": "def evaluate(self, formatter, kwargs, mi, locals, val, *args):\n if len(args) == 2: # here for backwards compatibility\n if val:\n return formatter.vformat('{'+args[0].strip()+'}', [], kwargs)\n else:\n return formatter.vformat('{'+args[1].strip()+'}', [], kwargs)\n if (len(args) % 2) != 1:\n raise ValueError(_('lookup requires either 2 or an odd number of arguments'))\n i = 0\n while i < len(args):\n if i + 1 >= len(args):\n return formatter.vformat('{' + args[i].strip() + '}', [], kwargs)\n if re.search(args[i], val):\n return formatter.vformat('{'+args[i+1].strip() + '}', [], kwargs)\n i += 2\n",
"template": "def evaluate(self, formatter, kwargs, mi, locals, template):\n template = template.replace('[[', '{').replace(']]', '}')\n return formatter.__class__().safe_format(template, kwargs, 'TEMPLATE', mi)\n",
@@ -23,14 +25,15 @@
"sublist": "def evaluate(self, formatter, kwargs, mi, locals, val, start_index, end_index, sep):\n if not val:\n return ''\n si = int(start_index)\n ei = int(end_index)\n val = val.split(sep)\n try:\n if ei == 0:\n return sep.join(val[si:])\n else:\n return sep.join(val[si:ei])\n except:\n return ''\n",
"test": "def evaluate(self, formatter, kwargs, mi, locals, val, value_if_set, value_not_set):\n if val:\n return value_if_set\n else:\n return value_not_set\n",
"eval": "def evaluate(self, formatter, kwargs, mi, locals, template):\n from formatter import eval_formatter\n template = template.replace('[[', '{').replace(']]', '}')\n return eval_formatter.safe_format(template, locals, 'EVAL', None)\n",
- "multiply": "def evaluate(self, formatter, kwargs, mi, locals, x, y):\n x = float(x if x else 0)\n y = float(y if y else 0)\n return unicode(x * y)\n",
+ "not": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n i = 0\n while i < len(args):\n if args[i]:\n return '1'\n i += 1\n return ''\n",
"format_date": "def evaluate(self, formatter, kwargs, mi, locals, val, format_string):\n if not val:\n return ''\n try:\n dt = parse_date(val)\n s = format_date(dt, format_string)\n except:\n s = 'BAD DATE'\n return s\n",
"capitalize": "def evaluate(self, formatter, kwargs, mi, locals, val):\n return capitalize(val)\n",
"count": "def evaluate(self, formatter, kwargs, mi, locals, val, sep):\n return unicode(len(val.split(sep)))\n",
"lowercase": "def evaluate(self, formatter, kwargs, mi, locals, val):\n return val.lower()\n",
- "strcmp": "def evaluate(self, formatter, kwargs, mi, locals, x, y, lt, eq, gt):\n v = strcmp(x, y)\n if v < 0:\n return lt\n if v == 0:\n return eq\n return gt\n",
- "switch": "def evaluate(self, formatter, kwargs, mi, locals, val, *args):\n if (len(args) % 2) != 1:\n raise ValueError(_('switch requires an odd number of arguments'))\n i = 0\n while i < len(args):\n if i + 1 >= len(args):\n return args[i]\n if re.search(args[i], val):\n return args[i+1]\n i += 2\n",
+ "substr": "def evaluate(self, formatter, kwargs, mi, locals, str_, start_, end_):\n return str_[int(start_): len(str_) if int(end_) == 0 else int(end_)]\n",
"assign": "def evaluate(self, formatter, kwargs, mi, locals, target, value):\n locals[target] = value\n return value\n",
+ "switch": "def evaluate(self, formatter, kwargs, mi, locals, val, *args):\n if (len(args) % 2) != 1:\n raise ValueError(_('switch requires an odd number of arguments'))\n i = 0\n while i < len(args):\n if i + 1 >= len(args):\n return args[i]\n if re.search(args[i], val):\n return args[i+1]\n i += 2\n",
+ "or": "def evaluate(self, formatter, kwargs, mi, locals, *args):\n i = 0\n while i < len(args):\n if args[i]:\n return '1'\n i += 1\n return ''\n",
"raw_field": "def evaluate(self, formatter, kwargs, mi, locals, name):\n return unicode(getattr(mi, name, None))\n",
"cmp": "def evaluate(self, formatter, kwargs, mi, locals, x, y, lt, eq, gt):\n x = float(x if x else 0)\n y = float(y if y else 0)\n if x < y:\n return lt\n if x == y:\n return eq\n return gt\n"
}
\ No newline at end of file
diff --git a/src/calibre/ebooks/mobi/mobiml.py b/src/calibre/ebooks/mobi/mobiml.py
index 3c36a6166d..2275552c15 100644
--- a/src/calibre/ebooks/mobi/mobiml.py
+++ b/src/calibre/ebooks/mobi/mobiml.py
@@ -297,9 +297,11 @@ class MobiMLizer(object):
if id_:
# Keep anchors so people can use display:none
# to generate hidden TOCs
+ tail = elem.tail
elem.clear()
elem.text = None
elem.set('id', id_)
+ elem.tail = tail
else:
return
tag = barename(elem.tag)
@@ -309,7 +311,8 @@ class MobiMLizer(object):
istates.append(istate)
left = 0
display = style['display']
- isblock = not display.startswith('inline')
+ isblock = (not display.startswith('inline') and style['display'] !=
+ 'none')
isblock = isblock and style['float'] == 'none'
isblock = isblock and tag != 'br'
if isblock:
diff --git a/src/calibre/gui2/dialogs/scheduler.py b/src/calibre/gui2/dialogs/scheduler.py
index b25d66979d..7d1d87b472 100644
--- a/src/calibre/gui2/dialogs/scheduler.py
+++ b/src/calibre/gui2/dialogs/scheduler.py
@@ -207,8 +207,9 @@ class SchedulerDialog(QDialog, Ui_Dialog):
self.recipe_model.searched.connect(self.search.search_done,
type=Qt.QueuedConnection)
self.recipe_model.searched.connect(self.search_done)
- self.search.setFocus(Qt.OtherFocusReason)
+ self.recipes.setFocus(Qt.OtherFocusReason)
self.commit_on_change = True
+ self.previous_urn = None
self.recipes.setModel(self.recipe_model)
self.detail_box.setVisible(False)
@@ -228,6 +229,9 @@ class SchedulerDialog(QDialog, Ui_Dialog):
self.old_news.setValue(gconf['oldest_news'])
+ self.go_button.clicked.connect(self.search.do_search)
+ self.clear_search_button.clicked.connect(self.search.clear_clicked)
+
def set_pw_echo_mode(self, state):
self.password.setEchoMode(self.password.Normal
if state == Qt.Checked else self.password.Password)
@@ -265,14 +269,9 @@ class SchedulerDialog(QDialog, Ui_Dialog):
self.last_downloaded.setVisible(enabled)
def current_changed(self, current, previous):
- if self.commit_on_change:
- if previous.isValid():
- if not self.commit(urn=getattr(previous.internalPointer(),
- 'urn', None)):
- self.commit_on_change = False
- self.recipes.setCurrentIndex(previous)
- else:
- self.commit_on_change = True
+ if self.previous_urn is not None:
+ self.commit(urn=self.previous_urn)
+ self.previous_urn = None
urn = self.current_urn
if urn is not None:
@@ -332,6 +331,7 @@ class SchedulerDialog(QDialog, Ui_Dialog):
return True
def initialize_detail_box(self, urn):
+ self.previous_urn = urn
self.detail_box.setVisible(True)
self.download_button.setVisible(True)
self.detail_box.setCurrentIndex(0)
diff --git a/src/calibre/gui2/dialogs/scheduler.ui b/src/calibre/gui2/dialogs/scheduler.ui
index f26bfc7285..6acbb01dd8 100644
--- a/src/calibre/gui2/dialogs/scheduler.ui
+++ b/src/calibre/gui2/dialogs/scheduler.ui
@@ -17,21 +17,30 @@
:/images/scheduler.png:/images/scheduler.png
-
+
-
-
-
- &Search:
-
-
- search
-
-
+
+
-
+
+
+ -
+
+
+ Go
+
+
+
+ -
+
+
+
+ :/images/clear_left.png:/images/clear_left.png
+
+
+
+
- -
-
-
- -
+
-
QFrame::NoFrame
@@ -44,7 +53,7 @@
0
0
- 486
+ 524
504
@@ -320,7 +329,7 @@
- -
+
-
@@ -345,7 +354,17 @@
- -
+
-
+
+
+
+
+
+ Qt::AlignCenter
+
+
+
+ -
-
@@ -376,17 +395,7 @@
- -
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Save
-
-
-
- -
+
-
Download all scheduled news sources at once
@@ -394,15 +403,19 @@
Download &all scheduled
+
+
+ :/images/news.png:/images/news.png
+
- -
-
-
-
+
-
+
+
+ Qt::Horizontal
-
- Qt::AlignCenter
+
+ QDialogButtonBox::Save