Commit 0e1df5d4 authored by SVN-Git Migration's avatar SVN-Git Migration

Imported Upstream version 2.0.8+ds1

parent ebfb096a
......@@ -2,6 +2,50 @@ ChangeLog of Frescobaldi, http://www.frescobaldi.org/
=====================================================
Changes in 2.0.8 -- September 14th, 2012
* Translations:
- updated: ru, cs
* New features:
- File->Open file at cursor (wish #84)
* Improvements:
- always normalize paths in point&click links, so files included via
constructs like \include "../songs/song1.ly" are found
* Bugfixes:
- fix behaviour of 'output' variable
Changes in 2.0.7 -- August 16th, 2012
* Translations:
- updated: nl, cs, it, fr, es
* New features:
- command to show music view maximized, useful on small screens
- kinetic scrolling in the music view, making the movements easier on the
eyes, contributed by Richard Cognot
- music view scrollbars can be hidden via preferences->tools->music view
* Improvements:
- status of "Always Engrave" is saved in session (wish #76)
- the 'View' -> 'Music View' submenu is now a top-level menu 'Music'
* Bugfixes:
- fix "NameError: global name 'X_OK' is not defined" when a helper application
has an absolute path
- fix python exception when helper app does not exist, now a regular message
is shown
Changes in 2.0.6 -- April 30th, 2012
* Translations:
- New Ukrainian translation by Dmytro O. Redchuk
- updated: nl
* Bugfixes:
- fix cut-assign
- fix startup failure on Windows when 'open in running app' is enabled and
the user's username has non-ascii characters (issue #53)
- fix TypeError on opening LilyPond documentation in some cases on Mac OS X
Changes in 2.0.5 -- April 25th, 2012
* Translations:
......
......@@ -11,15 +11,15 @@ under the General Public License.
Features:
- Powerful text editor with syntax highlighting and automatic completion
- Music view with advanced Point & Click
- Music view with advanced two-way Point & Click
- Midi player to proof-listen LilyPond-generated MIDI files
- Powerful Score Wizard to quickly setup a music score
- Snippet Manager to store and apply text snippets, templates or scripts
- Use multiple versions of LilyPond, automatically selects the correct version
- Built-in LilyPond documentation browser and built-in help
- Modern user iterface with configurable colors, fonts and keyboard shortcuts
- Translated into the following languages: Dutch, English, French, German,
Italian, Czech, Russian, Spanish, Galician, Turkish, Polish and Brazillian.
- Translated into: Dutch, English, French, German, Italian, Czech, Russian,
Spanish, Galician, Turkish, Polish, Brazillian and Ukrainian.
Music functions:
......
......@@ -12,13 +12,17 @@ And thanks to the LilyPond developers for creating an amazing music engraver!
Main author and core developer:
* Wilbert Berendsen (www.wilbertberendsen.nl)
Other developers:
* Richard Cognot: implemented Kinetic Scrolling for the music view
French translation:
* Raphaël Doursenaud
* Philippe Massart
* Valentin Villenave (valentin.villenave.info)
* Yann Collette
* David Bouriaud
* Ryan Kavanagh
* Ryan Kavanagh (also: Debian/Ubuntu packaging)
* Richard Cognot
Turkish translation:
* Server ACİM (www.serveracim.net)
......@@ -29,6 +33,7 @@ Spanish translation:
Russian translation:
* Sergey Poltavski
* Artem Zolochevskiy
* Mikhail Iglizky
Italian translation:
* Gianluca D'Orazio
......@@ -50,6 +55,9 @@ Galician translation:
Brazillian translation:
* Édio Mazera
Ukrainian translation:
* Dmytro O. Redchuk
Finding lots of bugs:
* Mario Moles
......@@ -57,6 +57,14 @@ def credits():
"Most of the bundled icons are created by {tango}.").format(
tango='<a href="http://tango.freedesktop.org/">{0}</a>'.format(_(
"The Tango Desktop Project")))
yield _("The following people contributed to {appname}:").format(
appname=info.appname)
# list other credits here
yield _("{author}: Kinetic Scrolling for the Music View").format(
author="Richard Cognot")
# translations
yield _(
"{appname} is translated into the following languages:").format(
appname=info.appname)
......
......@@ -204,6 +204,7 @@ class Dialog(QDialog):
with qutil.busyCursor():
try:
proc = subprocess.Popen(command,
universal_newlines = True,
env = env,
stdin = subprocess.PIPE,
stdout = subprocess.PIPE,
......
......@@ -86,7 +86,7 @@ def cut_assign(cursor):
text = ''.join((name, ' =', mode, ' {', space, text, space, '}\n\n'))
with cursortools.compress_undo(cursor):
cursor.insertText('\\' + name)
if metainfo.info(cursor.document()).autoindent:
if metainfo.info(cursor.document()).auto_indent:
indent.insert_text(insert, text)
else:
insert.insertText(text)
......
......@@ -95,6 +95,8 @@ class Document(QTextDocument):
try:
with open(fileName, "w") as f:
f.write(self.encodedText())
f.flush()
os.fsync(f.fileno())
except (IOError, OSError):
return False
self.setModified(False)
......
......@@ -43,6 +43,7 @@ class DocumentActions(plugin.MainWindowPlugin):
def __init__(self, mainwindow):
ac = self.actionCollection = Actions()
actioncollectionmanager.manager(mainwindow).addActionCollection(ac)
ac.file_open_file_at_cursor.triggered.connect(self.openFileAtCursor)
ac.edit_cut_assign.triggered.connect(self.cutAssign)
ac.view_highlighting.triggered.connect(self.toggleHighlighting)
ac.tools_indent_auto.triggered.connect(self.toggleAuto_indent)
......@@ -76,6 +77,11 @@ class DocumentActions(plugin.MainWindowPlugin):
if i is not self and i.currentDocument() == doc:
i.updateDocActions(doc)
def openFileAtCursor(self):
import open_file_at_cursor
open_file_at_cursor.open_file_at_cursor(self.currentView().textCursor(),
self.mainwindow())
def cutAssign(self):
import cut_assign
cut_assign.cut_assign(self.currentView().textCursor())
......@@ -108,6 +114,7 @@ class DocumentActions(plugin.MainWindowPlugin):
class Actions(actioncollection.ActionCollection):
name = "documentactions"
def createActions(self, parent):
self.file_open_file_at_cursor = QAction(parent)
self.edit_cut_assign = QAction(parent)
self.view_highlighting = QAction(parent)
self.view_highlighting.setCheckable(True)
......@@ -119,9 +126,11 @@ class Actions(actioncollection.ActionCollection):
self.edit_cut_assign.setIcon(icons.get('edit-cut'))
self.file_open_file_at_cursor.setShortcut(QKeySequence("Alt+Ctrl+O"))
self.edit_cut_assign.setShortcut(QKeySequence(Qt.SHIFT + Qt.CTRL + Qt.Key_X))
def translateUI(self):
self.file_open_file_at_cursor.setText(_("Open File at C&ursor"))
self.edit_cut_assign.setText(_("Cut and Assign..."))
self.view_highlighting.setText(_("Syntax &Highlighting"))
self.tools_indent_auto.setText(_("&Automatic Indent"))
......
......@@ -273,13 +273,14 @@ class DocumentInfo(plugin.DocumentPlugin):
output = fileinfo.FileInfo.info(filename).variables().get('output')
else:
output = variables.get(self.document(), 'output')
filename, mode = self.jobinfo()[:2]
if output:
dirname = os.path.dirname(filename)
return [os.path.join(dirname, name.strip())
for name in output.split(',')]
filename, mode = self.jobinfo()[:2]
if mode == "lilypond":
return fileinfo.basenames(filename, self.includefiles(), self.outputargs())
......
......@@ -23,7 +23,7 @@ Actions to engrave the music in the documents.
from __future__ import unicode_literals
from PyQt4.QtCore import QSettings, Qt
from PyQt4.QtCore import QSettings, Qt, QUrl
from PyQt4.QtGui import QAction, QApplication, QKeySequence
import app
......@@ -56,6 +56,8 @@ class Engraver(plugin.MainWindowPlugin):
mainwindow.currentDocumentChanged.connect(self.updateActions)
app.jobStarted.connect(self.updateActions)
app.jobFinished.connect(self.updateActions)
app.sessionChanged.connect(self.slotSessionChanged)
app.saveSessionData.connect(self.slotSaveSessionData)
app.languageChanged.connect(self.updateStickyActionText)
self.updateStickyActionText()
......@@ -178,7 +180,29 @@ class Engraver(plugin.MainWindowPlugin):
else:
text = _("&Always Engrave This Document")
self.actionCollection.engrave_sticky.setText(text)
def slotSessionChanged(self):
"""Called when the session is changed."""
import sessions
g = sessions.currentSessionGroup()
if g:
url = g.value("sticky_url", QUrl())
if not url.isEmpty():
d = app.findDocument(url)
if d:
self.setStickyDocument(d)
def slotSaveSessionData(self):
"""Called when a session needs to save data."""
import sessions
d = self.stickyDocument()
g = sessions.currentSessionGroup()
if g:
if d and not d.url().isEmpty():
g.setValue("sticky_url", d.url())
else:
g.remove("sticky_url")
class Actions(actioncollection.ActionCollection):
name = "engrave"
......
......@@ -29,7 +29,7 @@ import subprocess
import sys
from PyQt4.QtCore import QSettings
from PyQt4.QtGui import QDesktopServices
from PyQt4.QtGui import QDesktopServices, QMessageBox
def command(type):
......@@ -42,7 +42,7 @@ def command(type):
if not cmd:
return
if os.path.isabs(cmd) and os.access(cmd, X_OK):
if os.path.isabs(cmd) and os.access(cmd, os.X_OK):
return [cmd]
# remove double quotes, keeping quoted parts together
......@@ -95,7 +95,12 @@ def openUrl(url, type="browser"):
elif type != "shell":
cmd.append(url.toLocalFile())
subprocess.Popen([prog] + cmd, cwd=workdir)
try:
subprocess.Popen([prog] + cmd, cwd=workdir)
except OSError:
QMessageBox.critical(None, _("Error"), _(
"Could not start {program}.\n"
"Please check path and permissions.").format(program=prog))
def terminalCommands():
......
......@@ -26,7 +26,7 @@ from __future__ import unicode_literals
# these variables are also used by the distutils setup
name = "frescobaldi"
version = "2.0.5"
version = "2.0.8"
description = "LilyPond Music Editor"
long_description = \
"Frescobaldi is an advanced text editor to edit LilyPond sheet music files. " \
......@@ -51,6 +51,7 @@ translators = {
"Yann Collette",
"David Bouriaud",
"Ryan Kavanagh",
"Richard Cognot",
],
'tr': [
"Server ACİM",
......@@ -61,6 +62,7 @@ translators = {
'ru': [
"Sergey Poltavski",
"Artem Zolochevskiy",
"Mikhail Iglizky",
],
'it': [
"Gianluca D'Orazio",
......@@ -82,5 +84,8 @@ translators = {
'pt_BR': [
"Édio Mazera",
],
'uk': [
"Dmytro O. Redchuk",
],
}
......@@ -1744,7 +1744,7 @@ language_names = {
"ce":"Chechen",
"ch":"Chamorro",
"co":"Corsicaans",
"crh":"Krimtartaar",
"crh":"Krim-Tataars",
"cs":"Tsjechisch",
"csb":"Kashubian",
"cu":"Kerk Slavisch",
......@@ -1884,7 +1884,7 @@ language_names = {
"to":"Tonga",
"tr":"Turks",
"ts":"Tsonga",
"tt":"Tatar",
"tt":"Tataars",
"tw":"Twi",
"ty":"Tahitiaans",
"ug":"Oeigoers",
......@@ -2136,8 +2136,8 @@ language_names = {
"dz":"Dzongkha",
"el":"Grego",
"en":"Inglês",
"en_GB":"Inglês Britânico",
"en_US":"Inglês Americano",
"en_GB":"Inglês britânico",
"en_US":"Inglês americano",
"eo":"Esperanto",
"es":"Espanhol",
"et":"Estoniano",
......@@ -2148,13 +2148,13 @@ language_names = {
"fo":"Feroês",
"fr":"Francês",
"fy":"Frisão",
"ga":"Gaélico Irlandês",
"ga":"Gaélico irlandês",
"gd":"Gaélico",
"gl":"Galego",
"gn":"Guarani",
"gu":"Gujerati",
"gu":"Guzerate",
"gv":"Manês",
"ha":"Haússa",
"ha":"Haussá",
"he":"Hebraico",
"hi":"Hindi",
"hne":"Chhattisgarhi",
......@@ -2214,7 +2214,7 @@ language_names = {
"nl":"Holandês",
"nn":"Novo Norueguês",
"nr":"Ndebele do Sul",
"nso":"Sotho Setentrional",
"nso":"Sotho setentrional",
"nv":"Navajo",
"ny":"Cinianja",
"oc":"Occitano",
......@@ -2667,6 +2667,196 @@ language_names = {
"zh_TW":"Geleneksel Çince",
"zu":"Zulu",
},
"uk": {
"aa":"Афар",
"ab":"Абхазька",
"ae":"Авестан",
"af":"Африкаанс",
"am":"Амхарська",
"ar":"Арабська",
"as":"Асамійська",
"ast":"Астурійська",
"ay":"Аймарська",
"az":"Азербайджанська",
"ba":"Башкирська",
"be":"Білоруська",
"be@latin":"Білоруська (латиниця)",
"bg":"Болгарська",
"bh":"Біхарі",
"bi":"Біслама",
"bn":"Бенгальська",
"bn_IN":"Бенгальська (Індія)",
"bo":"Тибетська",
"br":"Бретонська",
"bs":"Боснійська",
"ca":"Каталонська",
"ca@valencia":"Каталонська (валенсійський діалект)",
"ce":"Чеченська",
"ch":"Чаморо",
"co":"Корсиканська",
"crh":"Кримсько-татарська",
"cs":"Чеська",
"csb":"Кашубська",
"cu":"Церковнослов'янська",
"cv":"Чуваська",
"cy":"Уельська",
"da":"Данська",
"de":"Німецька",
"dsb":"Нижньолужицька",
"dz":"Дзонг-ке",
"el":"Грецька",
"en":"Англійська",
"en_GB":"Англійська (Великобританія)",
"en_US":"Англійська (США)",
"eo":"Есперанто",
"es":"Іспанська",
"et":"Естонська",
"eu":"Баскська",
"fa":"Фарсі (Перська)",
"fi":"Фінська",
"fj":"Фіджійська",
"fo":"Фарерська",
"fr":"Французька",
"fy":"Фризька",
"ga":"Гаельська (Ірландія)",
"gd":"Гаельська",
"gl":"Галісійська",
"gn":"Гуарані",
"gu":"Гуджараті",
"gv":"Манкс",
"ha":"Гауса",
"he":"Єврейська",
"hi":"Хінді",
"hne":"Чхатісгарі",
"ho":"Хірімоту",
"hr":"Хорватська",
"hsb":"Верхньолужицька",
"hu":"Угорська",
"hy":"Вірменська",
"hz":"Гереро",
"ia":"Інтерлінгва",
"id":"Індонезійська",
"ie":"Окциденталь",
"ik":"Інупіак",
"io":"Ідо",
"is":"Ісландська",
"it":"Італійська",
"iu":"Інуктітут",
"ja":"Японська",
"jv":"Яванська",
"ka":"Грузинська",
"ki":"Кікуйю",
"kk":"Казахська",
"kl":"Калаалісут",
"km":"Кхмерська",
"kn":"Каннада",
"ko":"Корейська",
"ks":"Кашмірська",
"ku":"Курдська",
"kv":"Комі",
"kw":"Корнійська",
"ky":"Киргизька",
"la":"Латинська",
"lb":"Люксембурзька",
"li":"Лімбурганська",
"ln":"Лінгала",
"lo":"Лаоська",
"lt":"Литовська",
"lv":"Латвійська",
"mai":"Майтхілі",
"mg":"Малагасійська",
"mh":"Маршальська",
"mi":"Маорі",
"mk":"Македонська",
"ml":"Малайська",
"mn":"Монгольська",
"mo":"Молдовська",
"mr":"Мараті",
"ms":"Малайська",
"mt":"Мальтійська",
"my":"Бірманська",
"na":"Науру",
"nb":"Норвезька (Bokmål)",
"nd":"Ндебелє, Північна",
"nds":"Нижньосаксонська",
"ne":"Непальська",
"ng":"Ндонга",
"nl":"Голландська",
"nn":"Норвезька (Nynorsk)",
"nr":"Ндебелє, Південна",
"nso":"Північне Сото",
"nv":"Навахо",
"ny":"Чічеванська",
"oc":"Оксітанська",
"om":"Оромо",
"or":"Орія",
"os":"Осетинська",
"pa":"Панджабська",
"pi":"Палі",
"pl":"Польська",
"ps":"Пуштунська",
"pt":"Португальська",
"pt_BR":"Бразильська португальська",
"qu":"Кечуа",
"rn":"Рунді",
"ro":"Румунська",
"rom":"Циганська",
"ru":"Російська",
"rw":"Кіньяруанда",
"sa":"Санскрит",
"sc":"Сардинська",
"sd":"Синдхі",
"se":"Північна Саамі",
"sg":"Санго",
"si":"Сингала",
"sk":"Словацька",
"sl":"Словенська",
"sm":"Самоанська",
"sn":"Шона",
"so":"Сомалійська",
"sq":"Албанська",
"sr":"Сербська",
"sr@ijekavian":"Сербська (ієкавиця)",
"sr@ijekavianlatin":"Сербська (ієкавиця, латиниця)",
"sr@latin":"Сербська (латиниця)",
"ss":"Свазі",
"st":"Сото, Південна",
"su":"Сунданська",
"sv":"Шведська",
"sw":"Суахілі",
"ta":"Тамільська",
"te":"Телугу",
"tg":"Таджицька",
"th":"Тайська",
"ti":"Тигринійська",
"tk":"Туркменська",
"tn":"Тсвана",
"to":"Тонга",
"tr":"Турецька",
"ts":"Цонґа",
"tt":"Татарська",
"tw":"Тві",
"ty":"Таїтянська",
"ug":"Уйгурська",
"uk":"Українська",
"ur":"Урду",
"uz":"Узбецька",
"uz@cyrillic":"Узбецька (Кирилиця)",
"ven":"Венда",
"vi":"В'єтнамська",
"vo":"Волапюк",
"wa":"Валлонська",
"wo":"Волоф",
"xh":"Хоза",
"yi":"Ідиш",
"yo":"Йоруба",
"za":"Чжуань",
"zh":"Китайська",
"zh_CN":"Китайська (спрощена)",
"zh_HK":"Китайська (Гонконг)",
"zh_TW":"Китайська (традиційна)",
"zu":"Зулуська",
},
"zh": {
"aa":"阿法尔语",
"ab":"阿布哈西亚语",
......
......@@ -44,7 +44,7 @@ This script needs not to be installed to be able to use the language_names packa
# lang_names = []
lang_names = [
"C", "en", "de", "fr", "es", "nl", "pl", "pt_BR",
"cs", "ru", "hu", "gl", "it", "tr",
"cs", "ru", "hu", "gl", "it", "tr", "uk",
"ja", "zh",
]
......
......@@ -63,7 +63,7 @@ def langs():
lang = locale.getdefaultlocale()[0]
except ValueError:
return []
elif lang == "none":
if not lang or lang == "none":
return []
if '_' in lang:
return [lang, lang.split('_')[0]]
......
......@@ -31,7 +31,7 @@ import os
import re
import sys
from PyQt4.QtCore import QSettings, QUrl
from PyQt4.QtCore import QSettings, QTimer, QUrl
from PyQt4.QtGui import QApplication, QTextCursor
from . import toplevel # Find all modules and packages as toplevel
......@@ -66,6 +66,17 @@ def parse_commandline():
dest="session")
parser.add_option('-n', '--new', action="store_true", default=False,
help=_("Always start a new instance"))
# Make sure debugger options are recognized as valid. These are passed automatically
# from PyDev in Eclipse to the inferior process.
if "pydevd" in sys.modules:
parser.add_option('-v', '--vm_type')
parser.add_option('-a', '--client')
parser.add_option('-p', '--port')
parser.add_option('-f', '--file')
parser.add_option('-o', '--output')
args = QApplication.arguments()
if os.name == 'nt' and args and 'python' in os.path.basename(args[0]).lower():
......@@ -105,7 +116,7 @@ def main():
import splashscreen
splashscreen.show()
remote.setup() # Start listening for IPC
QTimer.singleShot(0, remote.setup) # Start listening for IPC
import mainwindow # contains MainWindow class
import session # Initialize QSessionManager support
......
......@@ -55,6 +55,7 @@ def createMenus(mainwindow):
menu_file,
menu_edit,
menu_view,
menu_music,
menu_insert,
menu_lilypond,
menu_tools,
......@@ -88,6 +89,7 @@ def menu_file(mainwindow):
m.addAction(ac.file_open)
m.addAction(ac.file_open_recent)
m.addAction(ac.file_insert_file)
m.addAction(documentactions.get(mainwindow).actionCollection.file_open_file_at_cursor)
m.addAction(ac.file_open_current_directory)
m.addSeparator()
m.addAction(ac.file_save)
......@@ -154,7 +156,6 @@ def menu_view(mainwindow):
m.addAction(documentactions.get(mainwindow).actionCollection.view_highlighting)
m.addAction(sidebar.SideBarManager.instance(mainwindow).actionCollection.view_linenumbers)
m.addMenu(menu_view_folding(mainwindow))
m.addMenu(menu_view_music(mainwindow))
m.addSeparator()
ac = bookmarkmanager.BookmarkManager.instance(mainwindow).actionCollection
m.addAction(ac.view_bookmark)
......@@ -184,8 +185,8 @@ def menu_view_folding(mainwindow):
return m
def menu_view_music(mainwindow):
m = Menu(_("submenu title", "Music &View"), mainwindow)
def menu_music(mainwindow):
m = Menu(_("menu title", "&Music"), mainwindow)
ac = panelmanager.manager(mainwindow).musicview.actionCollection
m.addAction(ac.music_zoom_in)
......@@ -198,6 +199,8 @@ def menu_view_music(mainwindow):
m.addSeparator()
m.addAction(ac.music_jump_to_cursor)
m.addAction(ac.music_sync_cursor)
m.addSeparator()
m.addAction(ac.music_maximize)
return m
......
......@@ -187,6 +187,8 @@ class Widget(QWidget):
def slotTimeSliderChanged(self, value):
self._player.seek(value)
self._display.setTime(value)
if self._player.song():
self._display.setBeat(*self._player.song().beat(value)[1:])
def slotTimeSliderMoved(self, value):
self._display.setTime(value)
......
......@@ -97,6 +97,7 @@ class MusicViewPanel(panel.Panel):
ac.music_fit_width.triggered.connect(self.fitWidth)
ac.music_fit_height.triggered.connect(self.fitHeight)
ac.music_fit_both.triggered.connect(self.fitBoth)
ac.music_maximize.triggered.connect(self.maximize)
ac.music_jump_to_cursor.triggered.connect(self.jumpToCursor)
ac.music_sync_cursor.triggered.connect(self.toggleSyncCursor)
ac.music_copy_image.triggered.connect(self.copyImage)
......@@ -109,7 +110,7 @@ class MusicViewPanel(panel.Panel):
ac.music_prev_page.setEnabled(False)
self.actionCollection.music_sync_cursor.setChecked(
QSettings().value("musicview/sync_cursor", False) in (True, "true"))
def translateUI(self):
self.setWindowTitle(_("window title", "Music View"))
self.toggleViewAction().setText(_("&Music View"))
......@@ -207,7 +208,7 @@ class MusicViewPanel(panel.Panel):
def toggleSyncCursor(self):
QSettings().setValue("musicview/sync_cursor",
self.actionCollection.music_sync_cursor.isChecked())
def copyImage(self):
from . import image
image.copy(self)
......@@ -241,6 +242,7 @@ class Actions(actioncollection.ActionCollection):
self.music_fit_width = QAction(panel, checkable=True)
self.music_fit_height = QAction(panel, checkable=True)
self.music_fit_both = QAction(panel, checkable=True)
self.music_maximize = QAction(panel)
self.music_jump_to_cursor = QAction(panel)