diff --git a/src/main/java/pro/litvinovg/w2phtml/gui/ConfigurationReader.java b/src/main/java/pro/litvinovg/w2phtml/gui/ConfigurationReader.java
deleted file mode 100644
index b8be732..0000000
--- a/src/main/java/pro/litvinovg/w2phtml/gui/ConfigurationReader.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package pro.litvinovg.w2phtml.gui;
-
-import java.awt.Component;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-import javax.swing.JCheckBox;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JTextField;
-
-import com.sun.star.uno.XComponentContext;
-
-public class ConfigurationReader {
-	
-	HashMap<String,String> options = new HashMap<String,String>();
-	private XComponentContext context;
-	private String format = null;
-	private String inputFilePath = null;
-	private String outputFilePath = null;
-	private String metadataFilePath = null;
-	private JFrame frame;
-
-	public ConfigurationReader(HashMap<String, Component> configuration, XComponentContext context, JFrame frame) {
-		this.context = context;
-		this.frame = frame;
-		readOptions(configuration);
-	}
-
-	private void readOptions(HashMap<String, Component> configuration) {
-		Set<String> keys = configuration.keySet();
-		for (String optionName : keys) {
-			String optionValue = null;
-			Component component = configuration.get(optionName);
-			if (component.getClass().equals(JTextField.class)) {
-				optionValue = ((JTextField) component).getText();
-			} else if (component.getClass().equals(JCheckBox.class)) {
-				optionValue = Boolean.toString(((JCheckBox) component).isSelected());
-			} else if (component.getClass().equals(JLabel.class)) {
-				optionValue = ((JLabel) component).getText();
-			}
-			options.put(optionName, optionValue);
-
-		}
-		format = options.get("targetFormat");
-		options.remove("targetFormat");
-		inputFilePath = options.get("inputFile");
-		options.remove("inputFile");
-		outputFilePath = options.get("outputFile");
-		options.remove("outputFile");
-		metadataFilePath = options.get("csv_metadata");
-	}
-
-	public String[] getCommandLine() {
-		List<String> args = new ArrayList<String>();
-		args.add("-"+format);
-		for (String key: options.keySet()) {
-			String value = options.get(key);
-			if( value != null && !value.isEmpty()) {
-				args.add("-"+key);
-				args.add(value);
-			}
-		}
-		args.add(inputFilePath);
-		if (outputFilePath != null) {
-			args.add(outputFilePath);
-		}
-		String sout = "";
-		for (String val: args) {
-			sout += val+" ";;
-		}
-		//Debug.printLog(sout, context);
-		String[] array = args.toArray(new String[0]);
-		return array; 
-	}
-
-	public boolean isValid() {
-		if (format == null) {
-			return false;
-		}
-		if (inputFilePath == null) {
-			JOptionPane.showMessageDialog(frame, "Input file path is null");
-			return false;
-		}
-		File inputFile = new File(inputFilePath);
-		if (!inputFile.exists()) {
-			JOptionPane.showMessageDialog(frame, "Input file not exists");
-			return false;
-		}
-		if (!inputFile.canRead()){
-			JOptionPane.showMessageDialog(frame, "Input file can not be read");
-			return false;
-		}
-		if (metadataFilePath != null) {
-			File metadataFile = new File(metadataFilePath);
-			if (!metadataFile.exists()) {
-				JOptionPane.showMessageDialog(frame, "Metadata file not exists");
-				return false;
-			}
-			if (!metadataFile.canRead()) {
-				JOptionPane.showMessageDialog(frame, "Metadata file can not be read");
-				return false;
-			}
-		}
-		if (outputFilePath == null) {
-			File inputDir = inputFile.getParentFile();
-			if (!inputDir.canWrite()) {
-				JOptionPane.showMessageDialog(frame, "Output directory is not writable");
-				return false;
-			}
-		} else {
-			File outputFile = new File(outputFilePath);
-			if (!outputFile.canWrite()) {
-				if (outputFile.isDirectory()) {
-					JOptionPane.showMessageDialog(frame, "Output directory is not writable");	
-				} else {
-					JOptionPane.showMessageDialog(frame, "Output file is not writable");
-				}
-				return false;
-			}
-		}
-
-		return true;
-	}
-
-}
diff --git a/src/main/java/pro/litvinovg/w2phtml/gui/ConfigurationWindow.java b/src/main/java/pro/litvinovg/w2phtml/gui/ConfigurationWindow.java
index aba47d4..445a7ca 100644
--- a/src/main/java/pro/litvinovg/w2phtml/gui/ConfigurationWindow.java
+++ b/src/main/java/pro/litvinovg/w2phtml/gui/ConfigurationWindow.java
@@ -598,18 +598,29 @@ public class ConfigurationWindow extends JFrame {
 		if (!inputFile.exists()) {
 			return;
 		}
-		File parent = inputFile.getParentFile();
-		if (parent == null) {
-			return;
-		}
-		if (!parent.canWrite()){
-			JOptionPane.showMessageDialog(singleFrame, "Attension. Output file can not be written.");
+		if (!inputFile.isDirectory()) {
+			File parent = inputFile.getParentFile();
+			if (parent == null) {
+				return;
+			}
+			if (!parent.canWrite()){
+				JOptionPane.showMessageDialog(singleFrame, "Attension. Can't save file in output directory.");
+			}
 		}
 		if (newFilePath.length() < 3) {
 			return;
 		}
-		String outputPath = newFilePath.substring(0, newFilePath.length()-3) + extension;
-		tf_OutputFile.setText(outputPath);
+		String exportPath;
+		if (inputFile.isDirectory()) {
+			exportPath = newFilePath;	
+			tf_OutputFile.setText(exportPath);
+		} else {
+			String importExt = newFilePath.substring(newFilePath.length()-3, newFilePath.length()).toLowerCase();
+			if (importExt.equals("odt")) {
+				exportPath = newFilePath.substring(0, newFilePath.length()-3) + extension;	
+				tf_OutputFile.setText(exportPath);
+			}
+		}
 	}
 
 	protected void setMetadataFilePath(String newFilePath, JTextField tf_MetadataFile, String extension) {
@@ -618,19 +629,25 @@ public class ConfigurationWindow extends JFrame {
 		if (!inputFile.exists()) {
 			return;
 		}
-		File parent = inputFile.getParentFile();
-		if (parent == null) {
-			return;
+		if (inputFile.isDirectory()) {
+			tf_MetadataFile.setText(newFilePath);	
+		} else {
+			File parent = inputFile.getParentFile();
+			if (parent == null) {
+				return;
+			}
+			if (newFilePath.length() < 3) {
+				return;
+			}
+			String importExt = newFilePath.substring(newFilePath.length()-3, newFilePath.length()).toLowerCase();
+			if (importExt.equals("odt")) {
+				String metadataPath = newFilePath.substring(0, newFilePath.length()-3) + extension;
+				File metaFile = new File(metadataPath);
+				if (metaFile.exists() && metaFile.canRead()){
+					tf_MetadataFile.setText(metadataPath);	
+				}	
+			}
 		}
-		if (newFilePath.length() < 3) {
-			return;
-		}
-		String metadataPath = newFilePath.substring(0, newFilePath.length()-3) + extension;
-		File metaFile = new File(metadataPath);
-		if (metaFile.exists() && metaFile.canRead()){
-			tf_MetadataFile.setText(metadataPath);	
-		}
-		
 	}
 
 	private JPanel createConfigRDFPanel(HashMap<String, Component> configuration) {
@@ -775,8 +792,8 @@ public class ConfigurationWindow extends JFrame {
 							.addComponent(lb_TargetFormat, GroupLayout.PREFERRED_SIZE, 111, GroupLayout.PREFERRED_SIZE))
 						.addComponent(cb_UseMathJax, GroupLayout.PREFERRED_SIZE, 303, GroupLayout.PREFERRED_SIZE)
 						.addGroup(gl_panel_configHTML.createSequentialGroup()
-							.addComponent(lb_FilterLetterSpacing, GroupLayout.PREFERRED_SIZE, 253, GroupLayout.PREFERRED_SIZE)
-							.addGap(18)
+							.addComponent(lb_FilterLetterSpacing, GroupLayout.PREFERRED_SIZE, 229, GroupLayout.PREFERRED_SIZE)
+							.addPreferredGap(ComponentPlacement.RELATED)
 							.addComponent(tf_FilterLetterSpacing, GroupLayout.PREFERRED_SIZE, 58, GroupLayout.PREFERRED_SIZE))
 						.addComponent(cb_convertToPx, GroupLayout.PREFERRED_SIZE, 592, GroupLayout.PREFERRED_SIZE)
 						.addComponent(cb_IgnoreHardLineBreaks, GroupLayout.PREFERRED_SIZE, 303, GroupLayout.PREFERRED_SIZE)
@@ -789,7 +806,7 @@ public class ConfigurationWindow extends JFrame {
 								.addGroup(gl_panel_configHTML.createSequentialGroup()
 									.addComponent(lb_metadataFilePath, GroupLayout.PREFERRED_SIZE, 131, GroupLayout.PREFERRED_SIZE)
 									.addPreferredGap(ComponentPlacement.RELATED)
-									.addComponent(tf_metadataPath))
+									.addComponent(tf_metadataPath, 600, 600, 600))
 								.addGroup(gl_panel_configHTML.createSequentialGroup()
 									.addComponent(lb_FilePath, GroupLayout.PREFERRED_SIZE, 111, GroupLayout.PREFERRED_SIZE)
 									.addGap(32)
@@ -838,22 +855,19 @@ public class ConfigurationWindow extends JFrame {
 						.addComponent(lb_type)
 						.addComponent(cbox_type, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
 					.addPreferredGap(ComponentPlacement.UNRELATED)
-					.addGroup(gl_panel_configHTML.createParallelGroup(Alignment.LEADING)
-						.addGroup(gl_panel_configHTML.createSequentialGroup()
-							.addGroup(gl_panel_configHTML.createParallelGroup(Alignment.BASELINE)
-								.addComponent(lb_Scale)
-								.addComponent(tf_Scale, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
-							.addPreferredGap(ComponentPlacement.RELATED)
-							.addComponent(lb_FilterLetterSpacing)
-							.addGap(4)
-							.addComponent(cb_InlineStyles)
-							.addGap(7)
-							.addComponent(cb_EmbedVectorImages)
-							.addGap(7)
-							.addComponent(cb_EmbedRaster))
-						.addGroup(gl_panel_configHTML.createSequentialGroup()
-							.addGap(6)
-							.addComponent(tf_FilterLetterSpacing, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
+					.addGroup(gl_panel_configHTML.createParallelGroup(Alignment.BASELINE)
+						.addComponent(lb_Scale)
+						.addComponent(tf_Scale, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+					.addPreferredGap(ComponentPlacement.RELATED)
+					.addGroup(gl_panel_configHTML.createParallelGroup(Alignment.BASELINE)
+						.addComponent(lb_FilterLetterSpacing)
+						.addComponent(tf_FilterLetterSpacing, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
+					.addGap(4)
+					.addComponent(cb_InlineStyles)
+					.addGap(7)
+					.addComponent(cb_EmbedVectorImages)
+					.addGap(7)
+					.addComponent(cb_EmbedRaster)
 					.addGap(7)
 					.addComponent(cb_convertToPx)
 					.addPreferredGap(ComponentPlacement.RELATED)
@@ -862,7 +876,7 @@ public class ConfigurationWindow extends JFrame {
 					.addComponent(cb_IgnoreEmptyParagraphs)
 					.addPreferredGap(ComponentPlacement.UNRELATED)
 					.addComponent(cb_UseMathJax)
-					.addContainerGap(280, Short.MAX_VALUE))
+					.addContainerGap(276, Short.MAX_VALUE))
 		);
 		panel_configHTML.setLayout(gl_panel_configHTML);
 		return panel_configHTML;
@@ -895,11 +909,8 @@ public class ConfigurationWindow extends JFrame {
 		btn_startConversion.addActionListener(new ActionListener() {
 			public void actionPerformed(ActionEvent actionEvent) {
 				try {
-				ConfigurationReader reader = new ConfigurationReader(configuration, context, singleFrame);
-				if (reader.isValid()) {
-					Application.main(reader.getCommandLine());
-					JOptionPane.showMessageDialog(singleFrame, "Conversion completed.");
-				}
+				ConversionExecutor executor = new ConversionExecutor(configuration, singleFrame);
+					executor.convert();
 				} catch(Throwable e) {
 					StringWriter errors = new StringWriter();
 					e.printStackTrace(new PrintWriter(errors));
diff --git a/src/main/java/pro/litvinovg/w2phtml/gui/ConversionExecutor.java b/src/main/java/pro/litvinovg/w2phtml/gui/ConversionExecutor.java
new file mode 100644
index 0000000..33dbf94
--- /dev/null
+++ b/src/main/java/pro/litvinovg/w2phtml/gui/ConversionExecutor.java
@@ -0,0 +1,241 @@
+package pro.litvinovg.w2phtml.gui;
+
+import java.awt.Component;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.JCheckBox;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import com.sun.star.uno.XComponentContext;
+
+import w2phtml.Application;
+
+public class ConversionExecutor {
+	
+	HashMap<String,String> options = new HashMap<String,String>();
+	private String format = null;
+	private String inputFilePath = null;
+	private String outputFilePath = null;
+	private String metadataFilePath = null;
+	private JFrame frame;
+
+	public ConversionExecutor(HashMap<String, Component> configuration, JFrame frame) {
+		this.frame = frame;
+		readOptions(configuration);
+	}
+
+	private void readOptions(HashMap<String, Component> configuration) {
+		Set<String> keys = configuration.keySet();
+		for (String optionName : keys) {
+			String optionValue = null;
+			Component component = configuration.get(optionName);
+			if (component.getClass().equals(JTextField.class)) {
+				optionValue = ((JTextField) component).getText();
+			} else if (component.getClass().equals(JCheckBox.class)) {
+				optionValue = Boolean.toString(((JCheckBox) component).isSelected());
+			} else if (component.getClass().equals(JLabel.class)) {
+				optionValue = ((JLabel) component).getText();
+			}
+			options.put(optionName, optionValue);
+
+		}
+		format = options.get("targetFormat");
+		options.remove("targetFormat");
+		inputFilePath = options.get("inputFile");
+		options.remove("inputFile");
+		outputFilePath = options.get("outputFile");
+		options.remove("outputFile");
+		metadataFilePath = options.get("csv_metadata");
+		options.remove("csv_metadata");
+
+	}
+
+	public String[] prepareArgs() {
+		List<String> args = new ArrayList<String>();
+		args.add("-"+format);
+		for (String key: options.keySet()) {
+			String value = options.get(key);
+			if( value != null && !value.isEmpty()) {
+				args.add("-"+key);
+				args.add(value);
+			}
+		}
+		if (metadataFilePath != null) {
+			args.add("-csv_metadata");
+			args.add(metadataFilePath);
+		}
+		args.add(inputFilePath);
+		if (outputFilePath != null) {
+			args.add(outputFilePath);
+		}
+		String[] array = args.toArray(new String[0]);
+		return array; 
+	}
+
+	public boolean isConfigValid() {
+		if (format == null) {
+			return false;
+		}
+		File inputFile = new File(inputFilePath);
+		File outputFile = null;
+		
+		if (!inputFile.exists()) {
+			JOptionPane.showMessageDialog(frame, "Input file not exists");
+			return false;
+		}
+		
+		if (!inputFile.canRead()){
+			JOptionPane.showMessageDialog(frame, "Input file can not be read");
+			return false;
+		}
+		
+		File metadataFile = null;
+		if (metadataFilePath != null && !metadataFilePath.trim().isEmpty()) {
+			metadataFile = new File(metadataFilePath);
+			if (!metadataFile.exists()) {
+				JOptionPane.showMessageDialog(frame, "Metadata file not exists");
+				return false;
+			}
+			if (!metadataFile.canRead()) {
+				JOptionPane.showMessageDialog(frame, "Metadata file can not be read");
+				return false;
+			}
+		}
+		if (outputFilePath == null || outputFilePath.trim().isEmpty()) {
+			File inputDir = inputFile.getParentFile();
+			if (!inputDir.canWrite()) {
+				JOptionPane.showMessageDialog(frame, "Output directory is not writable");
+				return false;
+			}
+		} else {
+			outputFile = new File(outputFilePath);
+			if (outputFile.exists()) {
+				if (!outputFile.canWrite()) {
+					if (outputFile.isDirectory()) {
+						JOptionPane.showMessageDialog(frame, "Output directory is not writable");	
+					} else {
+						JOptionPane.showMessageDialog(frame, outputFile.exists() + "Output file is not writable");
+					}
+					return false;	
+				}
+			} else {
+				try {
+					outputFile.createNewFile();
+					outputFile.delete();
+				} catch (IOException e) {
+					JOptionPane.showMessageDialog(frame, "Output file can not be created");	
+					return false;
+				}
+			}
+		}
+		
+		if (inputFile.isDirectory()) {
+			if (isAFile(outputFile)){
+				JOptionPane.showMessageDialog(frame, "Can't convert multiple inputs in one output");	
+				return false;
+			}
+			if (isAFile(metadataFile)){
+				JOptionPane.showMessageDialog(frame, "Can't convert multiple inputs with one metadata");	
+				return false;
+			}
+		} else {
+			if (metadataFile != null && metadataFile.isDirectory()){
+				JOptionPane.showMessageDialog(frame, "Can't convert one input file with multiple metadata files");	
+				return false;
+			}
+		}
+		
+		return true;
+	}
+
+	private boolean isAFile(File file) {
+		return file != null && (!file.exists() || !file.isDirectory());
+	}
+
+
+	public void convert() {
+		if (!isConfigValid()) {
+			return;
+		}
+		File inputFile = new File(inputFilePath);
+		if (inputFile.isDirectory()) {
+			convertAllInDir();
+		} else {
+			Application.main(prepareArgs());		
+			JOptionPane.showMessageDialog(frame, "Conversion completed.");	
+		}
+		
+	}
+
+	private void convertAllInDir() {
+		File inputDir = new File(inputFilePath);
+		if (!inputDir.isDirectory()) {
+			return;
+		}
+		File[] inputFiles = inputDir.listFiles(new FilenameFilter() {
+			@Override
+			public boolean accept(File dir, String name) {
+				return name.toLowerCase().endsWith("odt");
+			}
+		});
+		if (inputFiles.length == 0) {
+			JOptionPane.showMessageDialog(frame, "No ODT files in directory found.");
+			return;
+		}
+		String outputPath = outputFilePath;
+		String metadataDir = metadataFilePath;
+		for (File inputFile : inputFiles) {
+			convertFileInDir(inputFile, outputPath, metadataDir);
+		}
+		JOptionPane.showMessageDialog(frame, "Conversion completed.");
+
+	}
+
+	private void convertFileInDir(File inputFile, String outputPath, String metadataDir) {
+		String inputFileName = inputFile.getName();
+		//remove extension
+		inputFileName = inputFileName.substring(0, inputFileName.length() - 3);
+		if ("rdf".equals(format)){
+			String metadataInputFilePath = null;
+			if (metadataDir != null && !metadataDir.trim().isEmpty()) {
+				metadataInputFilePath = metadataDir + File.separator + inputFileName + "csv";
+			} else {
+				metadataInputFilePath = inputFile.getParent() + File.separator + inputFileName + "csv";				
+			}
+			File metadataFile = new File(metadataInputFilePath);
+			if (metadataFile.exists() && metadataFile.canRead()) {
+				metadataFilePath = metadataFile.getAbsolutePath();
+			} else {
+				metadataFilePath = null;
+			}
+		}
+		if (outputPath != null && !outputPath.isEmpty()) {
+			outputFilePath = outputPath + File.separator + inputFileName + getOutputExtension();
+		}
+		
+		inputFilePath = inputFile.getAbsolutePath();
+		Application.main(prepareArgs());		
+		
+	}
+
+	private String getOutputExtension() {
+		if (format.equals("rdf")) {
+			return "rdf";
+		} else if (format.equals("epub3")){
+			return "epub";
+		} else {
+			return "html";
+		}
+	}
+}