Skip to content

Commit

Permalink
Merge pull request #35 from IceTheDev2/bug-ctrl-c-does-not-work
Browse files Browse the repository at this point in the history
Bug ctrl c does not work
  • Loading branch information
IceTheCoder authored Feb 25, 2023
2 parents 854b9fc + f7690d1 commit c456942
Show file tree
Hide file tree
Showing 13 changed files with 249 additions and 210 deletions.
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions .idea/Passwordsy.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/inspectionProfiles/profiles_settings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

129 changes: 71 additions & 58 deletions code/generate_password_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@
no_character_set_error = 'An error occurred. Try again with at least 1 character set.'
double_error = 'An error occurred. Try again with at least 1 character set and a whole number between 4 and 100.'

global input_box
global copy_menu


def create_generate_password_frame(frame, done_btn_image) -> None:
'''
"""
Called upon starting the program,
this function uses the Tkinter module to create a GUI frame to generate passwords with various options for customisation
(length and character sets),
Expand All @@ -28,58 +32,58 @@ def create_generate_password_frame(frame, done_btn_image) -> None:
The "generate password" frame upon which the objects of this function will be placed.
done_btn_image: ImageTk.PhotoImage
The image used for the done button.
'''
password_label_1 = tk.Text(frame, width = password_width, height = password_height,
borderwidth = password_border_width, font = password_font)
password_label_2 = tk.Text(frame, width = password_width, height = password_height,
borderwidth = password_border_width, font = password_font)
password_label_3 = tk.Text(frame, width = password_width, height = password_height,
borderwidth = password_border_width, font = password_font)
password_label_4 = tk.Text(frame, width = password_width, height = password_height,
borderwidth = password_border_width, font = password_font)
"""
password_label_1 = tk.Text(frame, width=password_width, height=password_height,
borderwidth=password_border_width, font=password_font)
password_label_2 = tk.Text(frame, width=password_width, height=password_height,
borderwidth=password_border_width, font=password_font)
password_label_3 = tk.Text(frame, width=password_width, height=password_height,
borderwidth=password_border_width, font=password_font)
password_label_4 = tk.Text(frame, width=password_width, height=password_height,
borderwidth=password_border_width, font=password_font)
password_labels = [password_label_1, password_label_2, password_label_3, password_label_4]

frame_title = tk.Label(frame, text = 'Generate password', font = title_font)
frame_title.grid(column = 0, row = 1, columnspan = 2)

question = tk.Label(frame, text = 'Number of characters (4 to 100):', font = description_font)
question.grid(column = 0, row = 2, columnspan = 2)
frame_title = tk.Label(frame, text='Generate password', font=title_font)
frame_title.grid(column=0, row=1, columnspan=2)

character_sets_label = tk.Label(frame, text = 'Character sets', font = section_title_font)
character_sets_label.grid(column = 1, row = 4, columnspan = 2, sticky = 's')
question = tk.Label(frame, text='Number of characters (4 to 100):', font=description_font)
question.grid(column=0, row=2, columnspan=2)

character_sets_label = tk.Label(frame, text='Character sets', font=section_title_font)
character_sets_label.grid(column=1, row=5, columnspan=2)

lowercase_letters_var = tk.IntVar()
lowercase_letters_checkbox = tk.Checkbutton(frame, variable = lowercase_letters_var, offvalue = 0, onvalue = 1)
lowercase_letters_text = tk.Label(frame, text = 'Lowercase letters', font = description_font)
lowercase_letters_checkbox = tk.Checkbutton(frame, variable=lowercase_letters_var, offvalue=0, onvalue=1)
lowercase_letters_text = tk.Label(frame, text='Lowercase letters', font=description_font)

uppercase_letters_var = tk.IntVar()
uppercase_letters_checkbox = tk.Checkbutton(frame, variable = uppercase_letters_var, offvalue = 0, onvalue = 1)
uppercase_letters_text = tk.Label(frame, text = 'Uppercase letters', font = description_font)
uppercase_letters_checkbox = tk.Checkbutton(frame, variable=uppercase_letters_var, offvalue=0, onvalue=1)
uppercase_letters_text = tk.Label(frame, text='Uppercase letters', font=description_font)

digits_var = tk.IntVar()
digits_checkbox = tk.Checkbutton(frame, variable = digits_var, offvalue = 0, onvalue = 1)
digits_text = tk.Label(frame, text = 'Digits', font = description_font)
digits_checkbox = tk.Checkbutton(frame, variable=digits_var, offvalue=0, onvalue=1)
digits_text = tk.Label(frame, text='Digits', font=description_font)

punctuation_var = tk.IntVar()
punctuation_checkbox = tk.Checkbutton(frame, variable = punctuation_var, offvalue = 0, onvalue = 1)
punctuation_text = tk.Label(frame, text = 'Punctuation', font = description_font)
punctuation_checkbox = tk.Checkbutton(frame, variable=punctuation_var, offvalue=0, onvalue=1)
punctuation_text = tk.Label(frame, text='Punctuation', font=description_font)

checkboxes = [lowercase_letters_checkbox, uppercase_letters_checkbox, digits_checkbox, punctuation_checkbox]
checkboxes_text_labels = [lowercase_letters_text, uppercase_letters_text, digits_text, punctuation_text]

for checkbox in checkboxes:
checkbox.grid(column = 1, row = 5 + checkboxes.index(checkbox), pady = 8)
checkbox.grid(column=1, row=6 + checkboxes.index(checkbox), pady=8)
checkbox.select()

for text in checkboxes_text_labels:
text.grid(column = 2, row = 5 + checkboxes_text_labels.index(text), sticky = 'w')
text.grid(column=2, row=6 + checkboxes_text_labels.index(text), sticky='w')

def create_password_labels(event) -> None:
'''
"""
Called upon clicking the done button or pressing the ENTER key,
this function calls determine_error and validate_character_sets of generate_password_logic,
and then settles whether an error has occurred or not.
If an error has occurred, the function displays said error
If an error has occurred, the function displays said error
(obtained through determine_error),
and displays it on the screen through show_text.
If an error has not occurred, the function calls generate_password of generate_password_logic.py to get 4 passwords,
Expand All @@ -89,61 +93,70 @@ def create_password_labels(event) -> None:
----------
event:
Necessary for initiating the function when pressing the ENTER key.
'''
text = logic.determine_error(logic.validate_character_sets(lowercase_letters_var, uppercase_letters_var, digits_var, punctuation_var),
input_box.get(), no_character_set_error, double_error, invalid_input_error)
"""
for password_label in password_labels:
password_label.bind('<Button-3>', lambda e: logic.show_copy_button(e, copy_menu))

if text == '':
for password_label in password_labels:
password_label.bind('<ButtonRelease>', lambda event: logic.show_copy_button(event, copy_button))
message = logic.determine_error(
logic.validate_character_sets(lowercase_letters_var, uppercase_letters_var, digits_var, punctuation_var),
input_box.get(), no_character_set_error, double_error, invalid_input_error)

# Check if an error was not returned
if message == '':
for password_label in password_labels:
instruction_label.grid(column=0, row=5, sticky='s')
adapted_input = logic.adapt_input(input_box.get())
input_box.delete(0, 'end')
input_box.insert(1, adapted_input)
input_box.insert(1, str(adapted_input))

text = logic.generate_password(adapted_input, lowercase_letters_var, uppercase_letters_var, digits_var, punctuation_var)
show_text(password_label, text)
password_label.grid(column = 0, row = 5 + password_labels.index(password_label), pady = 10, padx = 10)
message = logic.generate_password(adapted_input, lowercase_letters_var, uppercase_letters_var,
digits_var, punctuation_var)
show_text(password_label, message)
password_label.grid(column=0, row=6 + password_labels.index(password_label), pady=10, padx=10)
else:
input_box.delete(0, 'end')
password_label_1.grid(column = 0, row = 5, padx = 10, pady = 10)
show_text(password_label_1, text)
password_label_1.grid(column=0, row=6, padx=10, pady=10)
show_text(password_label_1, message)

global input_box
input_box = tk.Entry(frame, width = 10, borderwidth = 2)
input_box = tk.Entry(frame, width=10, borderwidth=2)
input_box.bind('<Return>', create_password_labels)
input_box.grid(column = 0, row = 3, columnspan = 2)
input_box.grid(column=0, row=3, columnspan=2)

done_btn = tk.Button(frame, image = done_btn_image, borderwidth = 0, command = lambda: create_password_labels(None))
done_btn.grid(column = 0, row = 4, columnspan = 2)
done_btn = tk.Button(frame, image=done_btn_image, borderwidth=0, command=lambda: create_password_labels(None))
done_btn.grid(column=0, row=4, columnspan=2)

copy_button = tk.Menu(frame, tearoff = False)
copy_button.add_command(label = 'Copy', command = lambda: logic.copy_text(input_box, password_labels))
instruction_label = tk.Label(frame, text=' Right-click to copy', font=description_font)

def show_text(label, text) -> None:
'''
global copy_menu
copy_menu = tk.Menu(frame, tearoff=False)
copy_menu.add_command(label='Copy', command=lambda: logic.copy_text(input_box, password_labels))

def show_text(label, message) -> None:
"""
Called by the create_password_labels function,
this function updates the contents of the password_labels,
by enabling the label, deleting its current contents,
by enabling the label, deleting its current contents,
inserting the new text, and then disabling the label again.
Parameters
----------
label: tkinter.Text
Each password label one by one if passwords are generated,
or the first password label if an error is generated.
text: str
message: str
Each password or the error.
'''
label.config(state = 'normal')
"""
label.config(state='normal')
label.delete('1.0', 'end')
label.insert('1.0', text)
label.config(state = 'disabled', bg = '#ffffff')
label.insert('1.0', message)
label.config(state='disabled', bg='#ffffff')


def select_input_box(event) -> None:
'''
"""
Called whenever the tab is changed,
this function focuses the keyboard to the input box,
which allows the user to start typing immediately without having to click on the input box first.
'''
"""
input_box.focus()
64 changes: 37 additions & 27 deletions code/generate_password_logic.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import string
import secrets
import clipboard
from pynput.keyboard import Key, Controller
from pynput.keyboard import Controller

keyboard = Controller()


def adapt_input(requested_password_length) -> int:
'''
"""
Called by the create_password_labels function
(upon pressing the done button),
this function first checks if any input has been given.
Expand All @@ -20,28 +21,31 @@ def adapt_input(requested_password_length) -> int:
----------
requested_password_length: str
The input of the user.
'''
"""
if requested_password_length == '':
raise ValueError
else:
try:
return max(min(abs(int(round(float(requested_password_length), 0))), 100), 4)
except:
generated_password = max(min(abs(int(round(float(requested_password_length), 0))), 100), 4)
return generated_password
except ValueError:
raise ValueError

def determine_error(valid_character_set_bool, requested_password_length, no_character_set_error, double_error, invalid_input_error) -> str:
'''

def determine_error(valid_character_set_bool, requested_password_length, no_character_set_error, double_error,
invalid_input_error) -> str:
"""
Called by create_password_labels,
(upon pressing the done button)
this function retruns what error should be shown to the user:
this function returns what error should be shown to the user:
an invalid_input_error if a character set has been chosen, but the input is unadaptable.
a no_character_set_error if no character set has been chosen, but the input is adaptable,
or a double_error if no character set has been chosen, and the input is unadaptable.
Parameters
----------
valid_character_set_bool: boolean
Whether or not at least one character set has been chosen, as determined by validate_character_sets.
Whether at least one character set has been chosen, as determined by validate_character_sets.
requested_password_length: str
The input_box content.
no_character_set_error: str
Expand All @@ -50,23 +54,23 @@ def determine_error(valid_character_set_bool, requested_password_length, no_char
'An error occurred. Try again with at least 1 character set and a whole number between 4 and 100.'
invalid_input_error: str
'An error occurred. Try again with a whole number between 4 and 100.'
'''

"""
if valid_character_set_bool:
try:
adapt_input(requested_password_length)
return ''
except:
except ValueError:
return invalid_input_error
else:
try:
adapt_input(requested_password_length)
return no_character_set_error
except:
except ValueError:
return double_error

def validate_character_sets(lowercase_letters_var, uppercase_letters_var, digits_var, punctuation_var) -> str:
'''

def validate_character_sets(lowercase_letters_var, uppercase_letters_var, digits_var, punctuation_var) -> bool:
"""
Called by the create_password_labels function
(upon pressing the done button),
this function checks if at least one character set has been chosen by the user,
Expand All @@ -81,15 +85,18 @@ def validate_character_sets(lowercase_letters_var, uppercase_letters_var, digits
digits_var: tkinter.IntVar()
The variable of the digits checkbox.
punctuation_var: tkinter.IntVar()
The variable of the punctuation checkbox.
'''
if lowercase_letters_var.get() == 0 and uppercase_letters_var.get() == 0 and digits_var.get() == 0 and punctuation_var.get() == 0:
The variable of the punctuation checkbox.
"""
if lowercase_letters_var.get() == 0 and uppercase_letters_var.get() == 0 and digits_var.get() == 0 \
and punctuation_var.get() == 0:
return False
else:
return True

def generate_password(requested_password_length, lowercase_letters_var, uppercase_letters_var, digits_var, punctuation_var) -> str:
'''

def generate_password(requested_password_length, lowercase_letters_var, uppercase_letters_var, digits_var,
punctuation_var) -> str:
"""
Called by the validate_input function,
this function returns a password based on the user's requested length and on the selected character sets.
Expand All @@ -100,12 +107,12 @@ def generate_password(requested_password_length, lowercase_letters_var, uppercas
lowercase_letters_var: tkinter.IntVar()
The variable used to check if the lowercase letters checkbox has been selected or not.
uppercase_letters_var: tkinter.IntVar()
The variable used to check if the upprcase letters checkbox has been selected or not.
The variable used to check if the uppercase letters checkbox has been selected or not.
digits_var: tkinter.IntVar()
The variable used to check if the digits checkbox has been selected or not.
punctuation_var: tkinter.IntVar()
The variable used to check if the punctuation checkbox has been selected or not.
'''
"""
# Define all character sets that will be used in the password
character_sets = []
if lowercase_letters_var.get() == 1:
Expand All @@ -123,10 +130,12 @@ def generate_password(requested_password_length, lowercase_letters_var, uppercas
if all(any(char in s for char in password) for s in character_sets):
return password


def show_copy_button(event, copy) -> None:
'''
"""
Called when the user releases a mouse button on a password label,
this function uses the Tkinter module to display a contextual menu containing a 'copy' button for copying the password to the clipboard on the x and y coordinates of the user's cursor,
this function uses the Tkinter module to display a contextual menu containing a 'copy' button
for copying the password to the clipboard on the x and y coordinates of the user's cursor,
where the y coordinates are adjusted by 30 pixels.
Parameters
Expand All @@ -135,15 +144,16 @@ def show_copy_button(event, copy) -> None:
Gets the coordinates of the mouse cursor when the user releases a mouse button on a password_label.
copy: tkinter.Menu()
The copy button itself.
'''
"""
copy.tk_popup(event.x_root, event.y_root - 30)


def copy_text(input_box, labels) -> None:
'''
"""
Called upon pressing the copy button,
this function copies the selected text,
and focuses the keyboard on the input_box to deselect the text.
'''
"""
for label in labels:
selected_text = label.selection_get()
clipboard.copy(selected_text)
Expand Down
Loading

0 comments on commit c456942

Please sign in to comment.