This commit is contained in:
Dmitry Isaenko 2019-01-05 17:34:46 +03:00
parent c743b903da
commit 4e0ba6f086
43 changed files with 324 additions and 96 deletions

31
Jenkinsfile vendored Normal file
View file

@ -0,0 +1,31 @@
pipeline {
agent {
docker {
image 'maven:3-alpine'
args '-v /home/docker/jenkins/files/m2:/root/.m2'
}
}
stages {
stage('Build') {
steps {
sh 'mvn -B -DskipTests clean package'
}
}
stage('Test') {
steps {
echo 'Skip testing...'
}
}
stage('Deploy') {
steps {
echo 'Skip deployment...'
}
}
}
post {
always {
archiveArtifacts artifacts: 'target/*-jar-with-dependencies.jar', onlyIfSuccessful: true
}
}
}

View file

@ -1,60 +0,0 @@
package mplayer4anime;
/**
Name: mplayer4anime
@author Dmitry Isaenko
License: GNU GPL v.3
@version 0.11
@see https://developersu.blogspot.com/search/label/mplayer4anime
@see https://github.com/developersu/mplayer4anime
2018, Russia
*/
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import java.util.Locale;
import java.util.ResourceBundle;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("landingPage.fxml"));
if (Locale.getDefault().getISO3Language().equals("rus")) {
loader.setResources(ResourceBundle.getBundle("mplayer4anime.localization.locale", new Locale("ru")));
} else {
loader.setResources(ResourceBundle.getBundle("mplayer4anime.localization.locale", new Locale("en")));
}
Parent root = loader.load();
// tmp?
Controller controller = loader.getController();
controller.setHostServices(getHostServices());
// end
primaryStage.getIcons().addAll(
new Image(Main.class.getResourceAsStream("/mplayer4anime/res/app_icon32x32.png")),
new Image(Main.class.getResourceAsStream("/mplayer4anime/res/app_icon48x48.png")),
new Image(Main.class.getResourceAsStream("/mplayer4anime/res/app_icon64x64.png")),
new Image(Main.class.getResourceAsStream("/mplayer4anime/res/app_icon128x128.png"))
);
primaryStage.setTitle("mplayer4anime");
primaryStage.setMinWidth(500);
primaryStage.setMinHeight(375);
primaryStage.setScene(new Scene(root, 1200, 800));
// Make linkage to controller method to handle exit() event in there.
primaryStage.setOnHidden(e -> controller.shutdown());
primaryStage.show();
}
}

View file

@ -1,13 +1,13 @@
# mplayer4anime # mplayer4anime
mplayer4anime is mplayer launcher to play video file with audio layer and/or subtitles (.ass and .srt) at once. mplayer4anime is mplayer launcher to play video file with audio layer and/or subtitles (.ass, .srt, etc,,,) at once.
## License ## License
Source code spreads under the GNU General Public License v.3. You can find it in LICENSE file or just visit www.gnu.org (it should be there for sure). Source code spreads under the GNU General Public License v.3. You can find it in LICENSE file or just visit www.gnu.org (it should be there for sure).
Note: Since 0.10 application supports playlists management and implements own json-based format that (somehow) could be used in third-party application, Note: Since 0.10 application supports playlists management and implements own json-based format that (somehow) could be used in third-party application,
it would be nice to leave it as is. At least, I would prefer to have .alpr file extension used for this. As for the format of playlist format, please it would be nice to leave it as is. At least, I would prefer to have .alpr file extension used for this. As for the format of playlist, please
refer to WFTPL license. refer to WFTPL license.
## Used libraries ## Used libraries

Binary file not shown.

63
pom.xml Normal file
View file

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>loper</groupId>
<artifactId>mplayer4anime</artifactId>
<version>0.12-SNAPSHOT</version>
<packaging>jar</packaging>
<name>InnaIrcBot</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<archive>
<manifest>
<mainClass>
mplayer4anime.Main
</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

3
src/META-INF/MANIFEST.MF Normal file
View file

@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: mplayer4anime.Main

View file

@ -20,13 +20,13 @@ public class AboutWindow {
stageAbout.setMinWidth(500); stageAbout.setMinWidth(500);
stageAbout.setMinHeight(500); stageAbout.setMinHeight(500);
FXMLLoader loaderAbout = new FXMLLoader(getClass().getResource("AboutLayout.fxml")); FXMLLoader loaderAbout = new FXMLLoader(getClass().getResource("/About/AboutLayout.fxml"));
ResourceBundle resourceBundle; ResourceBundle resourceBundle;
if (Locale.getDefault().getISO3Language().equals("rus")) { if (Locale.getDefault().getISO3Language().equals("rus")) {
resourceBundle = ResourceBundle.getBundle("mplayer4anime.localization.locale", new Locale("ru")); resourceBundle = ResourceBundle.getBundle("locale", new Locale("ru"));
} else { } else {
resourceBundle = ResourceBundle.getBundle("mplayer4anime.localization.locale", new Locale("en")); resourceBundle = ResourceBundle.getBundle("locale", new Locale("en"));
} }
loaderAbout.setResources(resourceBundle); loaderAbout.setResources(resourceBundle);
@ -37,10 +37,10 @@ public class AboutWindow {
stageAbout.setTitle(resourceBundle.getString("about_AboutName")); stageAbout.setTitle(resourceBundle.getString("about_AboutName"));
stageAbout.getIcons().addAll( stageAbout.getIcons().addAll(
new Image(Main.class.getResourceAsStream("/mplayer4anime/res/app_icon32x32.png")), new Image(Main.class.getResourceAsStream("/res/app_icon32x32.png")),
new Image(Main.class.getResourceAsStream("/mplayer4anime/res/app_icon48x48.png")), new Image(Main.class.getResourceAsStream("/res/app_icon48x48.png")),
new Image(Main.class.getResourceAsStream("/mplayer4anime/res/app_icon64x64.png")), new Image(Main.class.getResourceAsStream("/res/app_icon64x64.png")),
new Image(Main.class.getResourceAsStream("/mplayer4anime/res/app_icon128x128.png")) new Image(Main.class.getResourceAsStream("/res/app_icon128x128.png"))
); // TODO: change to something reliable ); // TODO: change to something reliable
stageAbout.setScene(new Scene(parentAbout, 500, 500)); stageAbout.setScene(new Scene(parentAbout, 500, 500));

View file

@ -50,6 +50,13 @@ public class Controller implements Initializable {
private CheckMenuItem subsHide; private CheckMenuItem subsHide;
private String currentPlaylistLocation = null; //TODO: move to the constructor? private String currentPlaylistLocation = null; //TODO: move to the constructor?
// If application started with playlist passed as an argument, then we'll try to load it (if it's valid).
public void setPlaylistAsArgument(String playlist) {
JsonStorage jsonStorage = Playlists.ReadByPath(resourceBundle, new File(playlist));
setAllLists(jsonStorage);
}
@Override @Override
public void initialize(URL url, ResourceBundle rb) { public void initialize(URL url, ResourceBundle rb) {
mkvPaneController.setPaneType("Video"); mkvPaneController.setPaneType("Video");
@ -77,7 +84,7 @@ public class Controller implements Initializable {
addRecentlyOpened(recentPlaylists[i]); addRecentlyOpened(recentPlaylists[i]);
} }
public void setHostServices(HostServices hostServices) { void setHostServices(HostServices hostServices) {
this.hostServices = hostServices; this.hostServices = hostServices;
} }
@ -139,10 +146,19 @@ public class Controller implements Initializable {
} }
int index; int index;
index = mkvPaneController.getElementSelectedIndex(); index = mkvPaneController.getElementSelectedIndex();
// TODO: add 'link' button
if (index+1 < mkvPaneController.getElementsCount() ) { if (index+1 < mkvPaneController.getElementsCount() ) {
mkvPaneController.setElementSelectedByIndex(index+1); mkvPaneController.setElementSelectedByIndex(index+1);
playBtn();
} }
index = mkaPaneController.getElementSelectedIndex();
if (index+1 < mkaPaneController.getElementsCount() ) {
mkaPaneController.setElementSelectedByIndex(index+1);
}
index = subPaneController.getElementSelectedIndex();
if (index+1 < subPaneController.getElementsCount() ) {
subPaneController.setElementSelectedByIndex(index+1);
}
playBtn();
} }
private Process player; private Process player;
@ -225,7 +241,6 @@ public class Controller implements Initializable {
storeRecentArr[i] = (String) recentlyOpenedMenu.getItems().get(i).getUserData(); storeRecentArr[i] = (String) recentlyOpenedMenu.getItems().get(i).getUserData();
} }
appPreferences.setRecentPlaylists(storeRecentArr); appPreferences.setRecentPlaylists(storeRecentArr);
Platform.exit(); Platform.exit();
} }
@ -260,6 +275,7 @@ public class Controller implements Initializable {
subPaneController.selectEncodingValue(jsonStorage.getSubEncoding(), appPreferences); subPaneController.selectEncodingValue(jsonStorage.getSubEncoding(), appPreferences);
currentPlaylistLocation = Playlists.getPlaylistLocation(); // TODO: Implement listener? mmm... currentPlaylistLocation = Playlists.getPlaylistLocation(); // TODO: Implement listener? mmm...
//System.out.println(currentPlaylistLocation);
statusLbl.setText(currentPlaylistLocation); statusLbl.setText(currentPlaylistLocation);
addRecentlyOpened(currentPlaylistLocation); addRecentlyOpened(currentPlaylistLocation);
} }
@ -308,17 +324,10 @@ public class Controller implements Initializable {
MenuItem menuItem = new MenuItem(); MenuItem menuItem = new MenuItem();
String fileNameOnly; String fileNameOnly;
if (playlistPath.contains("/")) { // Unix
fileNameOnly = playlistPath.substring(playlistPath.lastIndexOf("/") + 1, playlistPath.length()); fileNameOnly = playlistPath.substring(playlistPath.lastIndexOf(File.separator) + 1);
menuItem.setText(fileNameOnly); menuItem.setText(fileNameOnly);
}
else if (playlistPath.contains("\\")) { // Windows
fileNameOnly = playlistPath.substring(playlistPath.lastIndexOf("\\") + 1, playlistPath.length());
menuItem.setText(fileNameOnly);
}
else { // Other o_0
menuItem.setText(playlistPath);
}
menuItem.setUserData(playlistPath); menuItem.setUserData(playlistPath);
menuItem.setOnAction(new EventHandler<ActionEvent>() { menuItem.setOnAction(new EventHandler<ActionEvent>() {
@Override @Override

View file

@ -0,0 +1,48 @@
package mplayer4anime.IPC;
import javafx.application.Platform;
import mplayer4anime.Controller;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
class ServerSocketProvider implements Runnable{
private ServerSocket serverSocket;
private Controller controller;
ServerSocketProvider(Controller mainCntrl, ServerSocket srvSock){
this.serverSocket = srvSock;
this.controller = mainCntrl;
}
@Override
public void run() {
Socket servSockClient;
try{
while (!serverSocket.isClosed()){
servSockClient = serverSocket.accept();
BufferedReader servInpRdr = new BufferedReader(
new InputStreamReader(servSockClient.getInputStream())
);
String line = servInpRdr.readLine();
// Avoid 'Not on FX application thread' error.
Platform.runLater(new Runnable() {
@Override
public void run() {
controller.setPlaylistAsArgument(line);
}
});
servSockClient.close();
}
}
catch (IOException ex){
System.out.println("Socket has been closed.");
}
}
}

View file

@ -0,0 +1,55 @@
package mplayer4anime.IPC;
import mplayer4anime.Controller;
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class SingleInstanceHandler implements Runnable{
private ServerSocket servSock;
public SingleInstanceHandler(Controller mainCntrl, String argument){
int PORT = 65042;
// Creating client server socket;
try {
servSock = new ServerSocket(PORT, 10, InetAddress.getLocalHost());
Thread ssp = new Thread(new ServerSocketProvider(mainCntrl, servSock));
ssp.start();
} catch (IOException e) {
if (argument != null){
// Creating client socket;
try {
Socket clientSocket = new Socket(InetAddress.getLocalHost(), PORT);
OutputStream outStream = clientSocket.getOutputStream();
OutputStreamWriter outStreamWriter = new OutputStreamWriter(outStream);
outStreamWriter.write(argument + "\n");
outStreamWriter.flush();
outStream.close();
clientSocket.close();
} catch (IOException ex){
System.out.println("Internal issue: unable to create client socket.");
}
}
else
System.out.println("Application is already running.");
System.exit(0);
}
}
@Override
public void run() {
while (true) {
if ( Thread.currentThread().isInterrupted() ){
try {
servSock.close();
} catch (IOException e) {
System.out.println("Internal issue: unable to create client socket.");
}
break;
}
}
}
}

View file

@ -0,0 +1,77 @@
package mplayer4anime;
/**
Name: mplayer4anime
@author Dmitry Isaenko
License: GNU GPL v.3
@version 0.12
@see https://developersu.blogspot.com/search/label/mplayer4anime
@see https://github.com/developersu/mplayer4anime
2018-2019, Russia
*/
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import mplayer4anime.IPC.SingleInstanceHandler;
import java.util.Locale;
import java.util.ResourceBundle;
//TODO: Use one copy of AppPreferences object widely
//TODO: Drag-n-drop playlist/files/audio
//TODO: remember selected
//TODO: remember position
public class Main extends Application {
public static void main(String[] args) { launch(args); }
@Override
public void start(Stage primaryStage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("/landingPage.fxml"));
if (Locale.getDefault().getISO3Language().equals("rus")) {
loader.setResources(ResourceBundle.getBundle("locale", new Locale("ru")));
} else {
loader.setResources(ResourceBundle.getBundle("locale", new Locale("en")));
}
Parent root = loader.load();
// tmp?
Controller controller = loader.getController();
controller.setHostServices(getHostServices());
SingleInstanceHandler sih;
if (!getParameters().getUnnamed().isEmpty())
sih = new SingleInstanceHandler(controller, getParameters().getUnnamed().get(0));
else
sih = new SingleInstanceHandler(controller, null);
// end
Thread tsih = new Thread(sih);
tsih.start();
// TODO: refactor needed?
Runtime.getRuntime().addShutdownHook(new Thread(() -> tsih.interrupt()));
primaryStage.getIcons().addAll(
new Image(Main.class.getResourceAsStream("/res/app_icon32x32.png")),
new Image(Main.class.getResourceAsStream("/res/app_icon48x48.png")),
new Image(Main.class.getResourceAsStream("/res/app_icon64x64.png")),
new Image(Main.class.getResourceAsStream("/res/app_icon128x128.png"))
);
primaryStage.setTitle("mplayer4anime");
primaryStage.setMinWidth(500);
primaryStage.setMinHeight(375);
primaryStage.setScene(new Scene(root, 1200, 800));
// Make linkage to controller method to handle exit() event in there.
primaryStage.setOnHidden(e -> {
tsih.interrupt();
controller.shutdown();
});
primaryStage.show();
}
}

View file

@ -5,6 +5,7 @@ import javafx.stage.FileChooser;
import mplayer4anime.ServiceWindow; import mplayer4anime.ServiceWindow;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ResourceBundle; import java.util.ResourceBundle;
public class Playlists { public class Playlists {
@ -45,7 +46,7 @@ public class Playlists {
if (!playlistFile.getAbsolutePath().endsWith(".alpr")) { if (!playlistFile.getAbsolutePath().endsWith(".alpr")) {
playlistFile = new File(playlistFile.getAbsolutePath() + ".alpr"); playlistFile = new File(playlistFile.getAbsolutePath() + ".alpr");
} }
try (Writer writer = new OutputStreamWriter(new FileOutputStream(playlistFile.getAbsolutePath()), "UTF-8")) try (Writer writer = new OutputStreamWriter(new FileOutputStream(playlistFile.getAbsolutePath()), StandardCharsets.UTF_8))
{ {
Gson jsonObject = new GsonBuilder().setPrettyPrinting().create(); Gson jsonObject = new GsonBuilder().setPrettyPrinting().create();
jsonObject.toJson(jStorage, writer); jsonObject.toJson(jStorage, writer);
@ -93,6 +94,7 @@ public class Playlists {
JsonStorage jStorage = new Gson().fromJson(reader, JsonStorage.class); JsonStorage jStorage = new Gson().fromJson(reader, JsonStorage.class);
if (jStorage != null){ if (jStorage != null){
playlistLocation = playlistFile.getAbsolutePath(); playlistLocation = playlistFile.getAbsolutePath();
//System.out.println("FILE:|"+playlistLocation+"|");
return jStorage; return jStorage;
} }
else else

View file

@ -19,13 +19,13 @@ public class SettingsWindow {
stageAbout.setMinWidth(570); stageAbout.setMinWidth(570);
stageAbout.setMinHeight(500); stageAbout.setMinHeight(500);
FXMLLoader loaderSettings = new FXMLLoader(getClass().getResource("SettingsLayout.fxml")); FXMLLoader loaderSettings = new FXMLLoader(getClass().getResource("/Settings/SettingsLayout.fxml"));
ResourceBundle resourceBundle; ResourceBundle resourceBundle;
if (Locale.getDefault().getISO3Language().equals("rus")) { if (Locale.getDefault().getISO3Language().equals("rus")) {
resourceBundle = ResourceBundle.getBundle("mplayer4anime.localization.locale", new Locale("ru")); resourceBundle = ResourceBundle.getBundle("locale", new Locale("ru"));
} else { } else {
resourceBundle = ResourceBundle.getBundle("mplayer4anime.localization.locale", new Locale("en")); resourceBundle = ResourceBundle.getBundle("locale", new Locale("en"));
} }
loaderSettings.setResources(resourceBundle); loaderSettings.setResources(resourceBundle);
@ -36,10 +36,10 @@ public class SettingsWindow {
stageAbout.setTitle(resourceBundle.getString("settings_SettingsName")); stageAbout.setTitle(resourceBundle.getString("settings_SettingsName"));
stageAbout.getIcons().addAll( stageAbout.getIcons().addAll(
new Image(Main.class.getResourceAsStream("/mplayer4anime/res/settings_icon32x32.png")), new Image(Main.class.getResourceAsStream("/res/settings_icon32x32.png")),
new Image(Main.class.getResourceAsStream("/mplayer4anime/res/settings_icon48x48.png")), new Image(Main.class.getResourceAsStream("/res/settings_icon48x48.png")),
new Image(Main.class.getResourceAsStream("/mplayer4anime/res/settings_icon64x64.png")), new Image(Main.class.getResourceAsStream("/res/settings_icon64x64.png")),
new Image(Main.class.getResourceAsStream("/mplayer4anime/res/settings_icon128x128.png")) new Image(Main.class.getResourceAsStream("/res/settings_icon128x128.png"))
); // TODO: change to something reliable ); // TODO: change to something reliable
stageAbout.setScene(new Scene(parentAbout, 570, 500)); stageAbout.setScene(new Scene(parentAbout, 570, 500));
stageAbout.show(); stageAbout.show();

View file

@ -1,5 +1,5 @@
about_line1=mplayer4amine distributes under GNU GPLv3 license. about_line1=mplayer4amine distributes under GNU GPLv3 license.
about_line2=Release: v0.11 about_line2=Release: v0.12
about_line3=Development & maintenance by Dmitry Isaenko. about_line3=Development & maintenance by Dmitry Isaenko.
about_AboutName=About about_AboutName=About
main_tab_audio=Audio main_tab_audio=Audio
@ -30,7 +30,7 @@ menu_File=File
menu_Tools=Tools menu_Tools=Tools
menu_Help=Help menu_Help=Help
menu_Help_AboutApp=About menu_Help_AboutApp=About
menu_File_Close=Close menu_File_Close=Exit
menu_Tools_Settings=Settings menu_Tools_Settings=Settings
menu_File_Open=Open playlist... menu_File_Open=Open playlist...
menu_File_Save=Save playlist menu_File_Save=Save playlist

View file

@ -1,6 +1,6 @@
menu_File_Recent=\u041F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0435 \u0444\u0430\u0439\u043B\u044B... menu_File_Recent=\u041F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0435 \u0444\u0430\u0439\u043B\u044B...
about_line1=mplayer4amine \u0440\u0430\u0441\u043F\u0440\u043E\u0441\u0442\u0440\u0430\u043D\u044F\u0435\u0442\u0441\u044F \u043F\u043E \u043B\u0438\u0446\u0435\u043D\u0437\u0438\u0438 GNU GPLv3. about_line1=mplayer4amine \u0440\u0430\u0441\u043F\u0440\u043E\u0441\u0442\u0440\u0430\u043D\u044F\u0435\u0442\u0441\u044F \u043F\u043E \u043B\u0438\u0446\u0435\u043D\u0437\u0438\u0438 GNU GPLv3.
about_line2=\u0420\u0435\u043B\u0438\u0437: v0.11 about_line2=\u0420\u0435\u043B\u0438\u0437: v0.12
about_line3=\u0420\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u0430\u043D\u043E \u0438 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F \u0414\u043C\u0438\u0442\u0440\u0438\u0435\u043C \u0418\u0441\u0430\u0435\u043D\u043A\u043E. about_line3=\u0420\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u0430\u043D\u043E \u0438 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F \u0414\u043C\u0438\u0442\u0440\u0438\u0435\u043C \u0418\u0441\u0430\u0435\u043D\u043A\u043E.
about_AboutName=\u041E \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438 about_AboutName=\u041E \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438
main_tab_audio=\u0410\u0443\u0434\u0438\u043E main_tab_audio=\u0410\u0443\u0434\u0438\u043E
@ -31,7 +31,7 @@ menu_File=\u0424\u0430\u0439\u043B
menu_Tools=\u0418\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B menu_Tools=\u0418\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B
menu_Help=\u0421\u043F\u0440\u0430\u0432\u043A\u0430 menu_Help=\u0421\u043F\u0440\u0430\u0432\u043A\u0430
menu_Help_AboutApp=\u041E \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438 menu_Help_AboutApp=\u041E \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438
menu_File_Close=\u0417\u0430\u043A\u0440\u044B\u0442\u044C menu_File_Close=\u0412\u044B\u0445\u043E\u0434
menu_Tools_Settings=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 menu_Tools_Settings=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438
menu_File_Open=\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u043F\u043B\u0435\u0439\u043B\u0438\u0441\u0442... menu_File_Open=\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u043F\u043B\u0435\u0439\u043B\u0438\u0441\u0442...
menu_File_Save=\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u043F\u043B\u0435\u0439\u043B\u0438\u0441\u0442 menu_File_Save=\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u043F\u043B\u0435\u0439\u043B\u0438\u0441\u0442

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

Before

Width:  |  Height:  |  Size: 4 KiB

After

Width:  |  Height:  |  Size: 4 KiB

View file

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View file

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View file

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View file

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

View file

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB