'source_path - æ¬å°æä»¶çç»å¯¹è·¯åŸ
dir_name    - æä»¶åšæå¡åšäžçç¶ç®åœ, åŠæäžºNoneçè¯, äŒåŒ¹åºäžäžª'

def upload_files(self, source_paths, dir_name=None):

    def scan_folders(folder_path):
        file_list = os.listdir(folder_path)
        source_paths = [os.path.join(folder_path, f) for f in file_list]
        self.upload_files(source_paths, os.path.join(dir_name, os.path.split(folder_path)[1]))
    self.check_first()
    if (not dir_name):
        folder_dialog = FolderBrowserDialog(self, self.app)
        response = folder_dialog.run()
        if (response != Gtk.ResponseType.OK):
            folder_dialog.destroy()
            return
        dir_name = folder_dialog.get_path()
        folder_dialog.destroy()
    invalid_paths = []
    for source_path in source_paths:
        if (util.validate_pathname(source_path) != ValidatePathState.OK):
            invalid_paths.append(source_path)
            continue
        if (os.path.split(source_path)[1].startswith('.') and (not self.app.profile['upload-hidden-files'])):
            continue
        if os.path.isfile(source_path):
            self.upload_file(source_path, dir_name)
        elif os.path.isdir(source_path):
            scan_folders(source_path)
    self.app.blink_page(self)
    self.scan_tasks()
    if (not invalid_paths):
        return
    dialog = Gtk.Dialog(_('Invalid    Filepath'), self.app.window, Gtk.DialogFlags.MODAL, (Gtk.STOCK_CLOSE, Gtk.ResponseType.OK))
    dialog.set_default_size(640, 480)
    dialog.set_border_width(10)
    box = dialog.get_content_area()
    scrolled_window = Gtk.ScrolledWindow()
    box.pack_start(scrolled_window, True, True, 0)
    text_buffer = Gtk.TextBuffer()
    textview = Gtk.TextView.new_with_buffer(text_buffer)
    scrolled_window.add(textview)
    for invalid_path in invalid_paths:
        text_buffer.insert_at_cursor(invalid_path)
        text_buffer.insert_at_cursor('\n')
    infobar = Gtk.InfoBar()
    infobar.set_message_type(Gtk.MessageType.ERROR)
    box.pack_end(infobar, False, False, 0)
    info_label = Gtk.Label()
    infobar.get_content_area().pack_start(info_label, False, False, 0)
    info_label.set_label(''.join(['*    ', ValidatePathStateText[1], '\n', '*    ', ValidatePathStateText[2], '\n', '*    ', ValidatePathStateText[3], '\n']))
    box.show_all()
    dialog.run()
    dialog.destroy()
